1use super::{attribute, WakeOp};
6use console_api as proto;
7use proto::resources::resource;
8use tracing_core::{
9 field::{self, Visit},
10 span,
11};
12
13const LOCATION_FILE: &str = "loc.file";
14const LOCATION_LINE: &str = "loc.line";
15const LOCATION_COLUMN: &str = "loc.col";
16const INHERIT_FIELD_NAME: &str = "inherits_child_attrs";
17
18#[derive(Default)]
36pub(crate) struct ResourceVisitor {
37 concrete_type: Option<String>,
38 kind: Option<resource::Kind>,
39 is_internal: bool,
40 inherit_child_attrs: bool,
41 line: Option<u32>,
42 file: Option<String>,
43 column: Option<u32>,
44}
45
46pub(crate) struct ResourceVisitorResult {
47 pub(crate) concrete_type: String,
48 pub(crate) kind: resource::Kind,
49 pub(crate) location: Option<proto::Location>,
50 pub(crate) is_internal: bool,
51 pub(crate) inherit_child_attrs: bool,
52}
53
54pub(crate) struct FieldVisitor {
57 fields: Vec<proto::Field>,
58 meta_id: proto::MetaId,
59}
60
61pub(crate) struct TaskVisitor {
84 field_visitor: FieldVisitor,
85 line: Option<u32>,
86 file: Option<String>,
87 column: Option<u32>,
88}
89
90#[derive(Default)]
102pub(crate) struct AsyncOpVisitor {
103 source: Option<String>,
104 inherit_child_attrs: bool,
105}
106
107#[derive(Default)]
121pub(crate) struct WakerVisitor {
122 id: Option<span::Id>,
123 op: Option<WakeOp>,
124}
125
126#[derive(Default)]
140pub(crate) struct PollOpVisitor {
141 op_name: Option<String>,
142 is_ready: Option<bool>,
143}
144
145pub(crate) struct StateUpdateVisitor {
162 meta_id: proto::MetaId,
163 field: Option<proto::Field>,
164 unit: Option<String>,
165 op: Option<attribute::UpdateOp>,
166}
167
168impl ResourceVisitor {
169 pub(crate) const RES_SPAN_NAME: &'static str = "runtime.resource";
170 const RES_CONCRETE_TYPE_FIELD_NAME: &'static str = "concrete_type";
171 const RES_VIZ_FIELD_NAME: &'static str = "is_internal";
172 const RES_KIND_FIELD_NAME: &'static str = "kind";
173 const RES_KIND_TIMER: &'static str = "timer";
174
175 pub(crate) fn result(self) -> Option<ResourceVisitorResult> {
176 let concrete_type = self.concrete_type?;
177 let kind = self.kind?;
178
179 let location = if self.file.is_some() && self.line.is_some() && self.column.is_some() {
180 Some(proto::Location {
181 file: self.file,
182 line: self.line,
183 column: self.column,
184 ..Default::default()
185 })
186 } else {
187 None
188 };
189
190 Some(ResourceVisitorResult {
191 concrete_type,
192 kind,
193 location,
194 is_internal: self.is_internal,
195 inherit_child_attrs: self.inherit_child_attrs,
196 })
197 }
198}
199
200impl Visit for ResourceVisitor {
201 fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
202
203 fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
204 match field.name() {
205 Self::RES_CONCRETE_TYPE_FIELD_NAME => self.concrete_type = Some(value.to_string()),
206 Self::RES_KIND_FIELD_NAME => {
207 let kind = Some(match value {
208 Self::RES_KIND_TIMER => {
209 resource::kind::Kind::Known(resource::kind::Known::Timer as i32)
210 }
211 other => resource::kind::Kind::Other(other.to_string()),
212 });
213 self.kind = Some(resource::Kind { kind });
214 }
215 LOCATION_FILE => self.file = Some(value.to_string()),
216 _ => {}
217 }
218 }
219
220 fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
221 match field.name() {
222 Self::RES_VIZ_FIELD_NAME => self.is_internal = value,
223 INHERIT_FIELD_NAME => self.inherit_child_attrs = value,
224 _ => {}
225 }
226 }
227
228 fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
229 match field.name() {
230 LOCATION_LINE => self.line = Some(value as u32),
231 LOCATION_COLUMN => self.column = Some(value as u32),
232 _ => {}
233 }
234 }
235}
236
237impl FieldVisitor {
238 pub(crate) fn new(meta_id: proto::MetaId) -> Self {
239 FieldVisitor {
240 fields: Vec::default(),
241 meta_id,
242 }
243 }
244 pub(crate) fn result(self) -> Vec<proto::Field> {
245 self.fields
246 }
247}
248
249impl TaskVisitor {
250 pub(crate) fn new(meta_id: proto::MetaId) -> Self {
251 TaskVisitor {
252 field_visitor: FieldVisitor::new(meta_id),
253 line: None,
254 file: None,
255 column: None,
256 }
257 }
258
259 pub(crate) fn result(self) -> (Vec<proto::Field>, Option<proto::Location>) {
260 let fields = self.field_visitor.result();
261 let location = if self.file.is_some() && self.line.is_some() && self.column.is_some() {
262 Some(proto::Location {
263 file: self.file,
264 line: self.line,
265 column: self.column,
266 ..Default::default()
267 })
268 } else {
269 None
270 };
271
272 (fields, location)
273 }
274}
275
276impl Visit for TaskVisitor {
277 fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
278 self.field_visitor.record_debug(field, value);
279 }
280
281 fn record_i64(&mut self, field: &tracing_core::Field, value: i64) {
282 self.field_visitor.record_i64(field, value);
283 }
284
285 fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
286 match field.name() {
287 LOCATION_LINE => self.line = Some(value as u32),
288 LOCATION_COLUMN => self.column = Some(value as u32),
289 _ => self.field_visitor.record_u64(field, value),
290 }
291 }
292
293 fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
294 self.field_visitor.record_bool(field, value);
295 }
296
297 fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
298 if field.name() == LOCATION_FILE {
299 self.file = Some(value.to_string());
300 } else {
301 self.field_visitor.record_str(field, value);
302 }
303 }
304}
305
306impl Visit for FieldVisitor {
307 fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
308 self.fields.push(proto::Field {
309 name: Some(field.name().into()),
310 value: Some(value.into()),
311 metadata_id: Some(self.meta_id),
312 });
313 }
314
315 fn record_i64(&mut self, field: &tracing_core::Field, value: i64) {
316 self.fields.push(proto::Field {
317 name: Some(field.name().into()),
318 value: Some(value.into()),
319 metadata_id: Some(self.meta_id),
320 });
321 }
322
323 fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
324 self.fields.push(proto::Field {
325 name: Some(field.name().into()),
326 value: Some(value.into()),
327 metadata_id: Some(self.meta_id),
328 });
329 }
330
331 fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
332 self.fields.push(proto::Field {
333 name: Some(field.name().into()),
334 value: Some(value.into()),
335 metadata_id: Some(self.meta_id),
336 });
337 }
338
339 fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
340 self.fields.push(proto::Field {
341 name: Some(field.name().into()),
342 value: Some(value.into()),
343 metadata_id: Some(self.meta_id),
344 });
345 }
346}
347
348impl AsyncOpVisitor {
349 pub(crate) const ASYNC_OP_SPAN_NAME: &'static str = "runtime.resource.async_op";
350 const ASYNC_OP_SRC_FIELD_NAME: &'static str = "source";
351
352 pub(crate) fn result(self) -> Option<(String, bool)> {
353 let inherit = self.inherit_child_attrs;
354 self.source.map(|s| (s, inherit))
355 }
356}
357
358impl Visit for AsyncOpVisitor {
359 fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
360
361 fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
362 if field.name() == Self::ASYNC_OP_SRC_FIELD_NAME {
363 self.source = Some(value.to_string());
364 }
365 }
366
367 fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
368 if field.name() == INHERIT_FIELD_NAME {
369 self.inherit_child_attrs = value;
370 }
371 }
372}
373
374impl WakerVisitor {
375 const WAKE: &'static str = "waker.wake";
376 const WAKE_BY_REF: &'static str = "waker.wake_by_ref";
377 const CLONE: &'static str = "waker.clone";
378 const DROP: &'static str = "waker.drop";
379 const TASK_ID_FIELD_NAME: &'static str = "task.id";
380
381 pub(crate) fn result(self) -> Option<(span::Id, WakeOp)> {
382 self.id.zip(self.op)
383 }
384}
385
386impl Visit for WakerVisitor {
387 fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {
388 }
390
391 fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
392 if field.name() == Self::TASK_ID_FIELD_NAME {
393 self.id = Some(span::Id::from_u64(value));
394 }
395 }
396
397 fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
398 if field.name() == "op" {
399 self.op = Some(match value {
400 Self::WAKE => WakeOp::Wake { self_wake: false },
401 Self::WAKE_BY_REF => WakeOp::WakeByRef { self_wake: false },
402 Self::CLONE => WakeOp::Clone,
403 Self::DROP => WakeOp::Drop,
404 _ => return,
405 });
406 }
407 }
408}
409
410impl PollOpVisitor {
411 pub(crate) const POLL_OP_EVENT_TARGET: &'static str = "runtime::resource::poll_op";
412 const OP_NAME_FIELD_NAME: &'static str = "op_name";
413 const OP_READINESS_FIELD_NAME: &'static str = "is_ready";
414
415 pub(crate) fn result(self) -> Option<(String, bool)> {
416 let op_name = self.op_name?;
417 let is_ready = self.is_ready?;
418 Some((op_name, is_ready))
419 }
420}
421
422impl Visit for PollOpVisitor {
423 fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
424
425 fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
426 if field.name() == Self::OP_READINESS_FIELD_NAME {
427 self.is_ready = Some(value)
428 }
429 }
430
431 fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
432 if field.name() == Self::OP_NAME_FIELD_NAME {
433 self.op_name = Some(value.to_string());
434 }
435 }
436}
437
438impl StateUpdateVisitor {
439 pub(crate) const RE_STATE_UPDATE_EVENT_TARGET: &'static str = "runtime::resource::state_update";
440 pub(crate) const AO_STATE_UPDATE_EVENT_TARGET: &'static str =
441 "runtime::resource::async_op::state_update";
442
443 const STATE_OP_SUFFIX: &'static str = ".op";
444 const STATE_UNIT_SUFFIX: &'static str = ".unit";
445
446 const OP_ADD: &'static str = "add";
447 const OP_SUB: &'static str = "sub";
448 const OP_OVERRIDE: &'static str = "override";
449
450 pub(crate) fn new(meta_id: proto::MetaId) -> Self {
451 StateUpdateVisitor {
452 meta_id,
453 field: None,
454 unit: None,
455 op: None,
456 }
457 }
458
459 pub(crate) fn result(self) -> Option<attribute::Update> {
460 Some(attribute::Update {
461 field: self.field?,
462 op: self.op,
463 unit: self.unit,
464 })
465 }
466}
467
468impl Visit for StateUpdateVisitor {
469 fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
470 if !field.name().ends_with(Self::STATE_OP_SUFFIX)
471 && !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
472 {
473 self.field = Some(proto::Field {
474 name: Some(field.name().into()),
475 value: Some(value.into()),
476 metadata_id: Some(self.meta_id),
477 });
478 }
479 }
480
481 fn record_i64(&mut self, field: &field::Field, value: i64) {
482 if !field.name().ends_with(Self::STATE_OP_SUFFIX)
483 && !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
484 {
485 self.field = Some(proto::Field {
486 name: Some(field.name().into()),
487 value: Some(value.into()),
488 metadata_id: Some(self.meta_id),
489 });
490 }
491 }
492
493 fn record_u64(&mut self, field: &field::Field, value: u64) {
494 if !field.name().ends_with(Self::STATE_OP_SUFFIX)
495 && !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
496 {
497 self.field = Some(proto::Field {
498 name: Some(field.name().into()),
499 value: Some(value.into()),
500 metadata_id: Some(self.meta_id),
501 });
502 }
503 }
504
505 fn record_bool(&mut self, field: &field::Field, value: bool) {
506 if !field.name().ends_with(Self::STATE_OP_SUFFIX)
507 && !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
508 {
509 self.field = Some(proto::Field {
510 name: Some(field.name().into()),
511 value: Some(value.into()),
512 metadata_id: Some(self.meta_id),
513 });
514 }
515 }
516
517 fn record_str(&mut self, field: &field::Field, value: &str) {
518 if field.name().ends_with(Self::STATE_OP_SUFFIX) {
519 match value {
520 Self::OP_ADD => self.op = Some(attribute::UpdateOp::Add),
521 Self::OP_SUB => self.op = Some(attribute::UpdateOp::Sub),
522 Self::OP_OVERRIDE => self.op = Some(attribute::UpdateOp::Override),
523 _ => {}
524 };
525 } else if field.name().ends_with(Self::STATE_UNIT_SUFFIX) {
526 self.unit = Some(value.to_string());
527 } else {
528 self.field = Some(proto::Field {
529 name: Some(field.name().into()),
530 value: Some(value.into()),
531 metadata_id: Some(self.meta_id),
532 });
533 }
534 }
535}