use super::{attribute, WakeOp};
use console_api as proto;
use proto::resources::resource;
use tracing_core::{
field::{self, Visit},
span,
};
const LOCATION_FILE: &str = "loc.file";
const LOCATION_LINE: &str = "loc.line";
const LOCATION_COLUMN: &str = "loc.col";
const INHERIT_FIELD_NAME: &str = "inherits_child_attrs";
#[derive(Default)]
pub(crate) struct ResourceVisitor {
concrete_type: Option<String>,
kind: Option<resource::Kind>,
is_internal: bool,
inherit_child_attrs: bool,
line: Option<u32>,
file: Option<String>,
column: Option<u32>,
}
pub(crate) struct ResourceVisitorResult {
pub(crate) concrete_type: String,
pub(crate) kind: resource::Kind,
pub(crate) location: Option<proto::Location>,
pub(crate) is_internal: bool,
pub(crate) inherit_child_attrs: bool,
}
pub(crate) struct FieldVisitor {
fields: Vec<proto::Field>,
meta_id: proto::MetaId,
}
pub(crate) struct TaskVisitor {
field_visitor: FieldVisitor,
line: Option<u32>,
file: Option<String>,
column: Option<u32>,
}
#[derive(Default)]
pub(crate) struct AsyncOpVisitor {
source: Option<String>,
inherit_child_attrs: bool,
}
#[derive(Default)]
pub(crate) struct WakerVisitor {
id: Option<span::Id>,
op: Option<WakeOp>,
}
#[derive(Default)]
pub(crate) struct PollOpVisitor {
op_name: Option<String>,
is_ready: Option<bool>,
}
pub(crate) struct StateUpdateVisitor {
meta_id: proto::MetaId,
field: Option<proto::Field>,
unit: Option<String>,
op: Option<attribute::UpdateOp>,
}
impl ResourceVisitor {
pub(crate) const RES_SPAN_NAME: &'static str = "runtime.resource";
const RES_CONCRETE_TYPE_FIELD_NAME: &'static str = "concrete_type";
const RES_VIZ_FIELD_NAME: &'static str = "is_internal";
const RES_KIND_FIELD_NAME: &'static str = "kind";
const RES_KIND_TIMER: &'static str = "timer";
pub(crate) fn result(self) -> Option<ResourceVisitorResult> {
let concrete_type = self.concrete_type?;
let kind = self.kind?;
let location = if self.file.is_some() && self.line.is_some() && self.column.is_some() {
Some(proto::Location {
file: self.file,
line: self.line,
column: self.column,
..Default::default()
})
} else {
None
};
Some(ResourceVisitorResult {
concrete_type,
kind,
location,
is_internal: self.is_internal,
inherit_child_attrs: self.inherit_child_attrs,
})
}
}
impl Visit for ResourceVisitor {
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
match field.name() {
Self::RES_CONCRETE_TYPE_FIELD_NAME => self.concrete_type = Some(value.to_string()),
Self::RES_KIND_FIELD_NAME => {
let kind = Some(match value {
Self::RES_KIND_TIMER => {
resource::kind::Kind::Known(resource::kind::Known::Timer as i32)
}
other => resource::kind::Kind::Other(other.to_string()),
});
self.kind = Some(resource::Kind { kind });
}
LOCATION_FILE => self.file = Some(value.to_string()),
_ => {}
}
}
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
match field.name() {
Self::RES_VIZ_FIELD_NAME => self.is_internal = value,
INHERIT_FIELD_NAME => self.inherit_child_attrs = value,
_ => {}
}
}
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
match field.name() {
LOCATION_LINE => self.line = Some(value as u32),
LOCATION_COLUMN => self.column = Some(value as u32),
_ => {}
}
}
}
impl FieldVisitor {
pub(crate) fn new(meta_id: proto::MetaId) -> Self {
FieldVisitor {
fields: Vec::default(),
meta_id,
}
}
pub(crate) fn result(self) -> Vec<proto::Field> {
self.fields
}
}
impl TaskVisitor {
pub(crate) fn new(meta_id: proto::MetaId) -> Self {
TaskVisitor {
field_visitor: FieldVisitor::new(meta_id),
line: None,
file: None,
column: None,
}
}
pub(crate) fn result(self) -> (Vec<proto::Field>, Option<proto::Location>) {
let fields = self.field_visitor.result();
let location = if self.file.is_some() && self.line.is_some() && self.column.is_some() {
Some(proto::Location {
file: self.file,
line: self.line,
column: self.column,
..Default::default()
})
} else {
None
};
(fields, location)
}
}
impl Visit for TaskVisitor {
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
self.field_visitor.record_debug(field, value);
}
fn record_i64(&mut self, field: &tracing_core::Field, value: i64) {
self.field_visitor.record_i64(field, value);
}
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
match field.name() {
LOCATION_LINE => self.line = Some(value as u32),
LOCATION_COLUMN => self.column = Some(value as u32),
_ => self.field_visitor.record_u64(field, value),
}
}
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
self.field_visitor.record_bool(field, value);
}
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
if field.name() == LOCATION_FILE {
self.file = Some(value.to_string());
} else {
self.field_visitor.record_str(field, value);
}
}
}
impl Visit for FieldVisitor {
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
self.fields.push(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
fn record_i64(&mut self, field: &tracing_core::Field, value: i64) {
self.fields.push(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
self.fields.push(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
self.fields.push(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
self.fields.push(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
}
impl AsyncOpVisitor {
pub(crate) const ASYNC_OP_SPAN_NAME: &'static str = "runtime.resource.async_op";
const ASYNC_OP_SRC_FIELD_NAME: &'static str = "source";
pub(crate) fn result(self) -> Option<(String, bool)> {
let inherit = self.inherit_child_attrs;
self.source.map(|s| (s, inherit))
}
}
impl Visit for AsyncOpVisitor {
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
if field.name() == Self::ASYNC_OP_SRC_FIELD_NAME {
self.source = Some(value.to_string());
}
}
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
if field.name() == INHERIT_FIELD_NAME {
self.inherit_child_attrs = value;
}
}
}
impl WakerVisitor {
const WAKE: &'static str = "waker.wake";
const WAKE_BY_REF: &'static str = "waker.wake_by_ref";
const CLONE: &'static str = "waker.clone";
const DROP: &'static str = "waker.drop";
const TASK_ID_FIELD_NAME: &'static str = "task.id";
pub(crate) fn result(self) -> Option<(span::Id, WakeOp)> {
self.id.zip(self.op)
}
}
impl Visit for WakerVisitor {
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {
}
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
if field.name() == Self::TASK_ID_FIELD_NAME {
self.id = Some(span::Id::from_u64(value));
}
}
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
if field.name() == "op" {
self.op = Some(match value {
Self::WAKE => WakeOp::Wake { self_wake: false },
Self::WAKE_BY_REF => WakeOp::WakeByRef { self_wake: false },
Self::CLONE => WakeOp::Clone,
Self::DROP => WakeOp::Drop,
_ => return,
});
}
}
}
impl PollOpVisitor {
pub(crate) const POLL_OP_EVENT_TARGET: &'static str = "runtime::resource::poll_op";
const OP_NAME_FIELD_NAME: &'static str = "op_name";
const OP_READINESS_FIELD_NAME: &'static str = "is_ready";
pub(crate) fn result(self) -> Option<(String, bool)> {
let op_name = self.op_name?;
let is_ready = self.is_ready?;
Some((op_name, is_ready))
}
}
impl Visit for PollOpVisitor {
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
if field.name() == Self::OP_READINESS_FIELD_NAME {
self.is_ready = Some(value)
}
}
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
if field.name() == Self::OP_NAME_FIELD_NAME {
self.op_name = Some(value.to_string());
}
}
}
impl StateUpdateVisitor {
pub(crate) const RE_STATE_UPDATE_EVENT_TARGET: &'static str = "runtime::resource::state_update";
pub(crate) const AO_STATE_UPDATE_EVENT_TARGET: &'static str =
"runtime::resource::async_op::state_update";
const STATE_OP_SUFFIX: &'static str = ".op";
const STATE_UNIT_SUFFIX: &'static str = ".unit";
const OP_ADD: &'static str = "add";
const OP_SUB: &'static str = "sub";
const OP_OVERRIDE: &'static str = "override";
pub(crate) fn new(meta_id: proto::MetaId) -> Self {
StateUpdateVisitor {
meta_id,
field: None,
unit: None,
op: None,
}
}
pub(crate) fn result(self) -> Option<attribute::Update> {
Some(attribute::Update {
field: self.field?,
op: self.op,
unit: self.unit,
})
}
}
impl Visit for StateUpdateVisitor {
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
{
self.field = Some(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
}
fn record_i64(&mut self, field: &field::Field, value: i64) {
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
{
self.field = Some(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
}
fn record_u64(&mut self, field: &field::Field, value: u64) {
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
{
self.field = Some(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
}
fn record_bool(&mut self, field: &field::Field, value: bool) {
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
{
self.field = Some(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
}
fn record_str(&mut self, field: &field::Field, value: &str) {
if field.name().ends_with(Self::STATE_OP_SUFFIX) {
match value {
Self::OP_ADD => self.op = Some(attribute::UpdateOp::Add),
Self::OP_SUB => self.op = Some(attribute::UpdateOp::Sub),
Self::OP_OVERRIDE => self.op = Some(attribute::UpdateOp::Override),
_ => {}
};
} else if field.name().ends_with(Self::STATE_UNIT_SUFFIX) {
self.unit = Some(value.to_string());
} else {
self.field = Some(proto::Field {
name: Some(field.name().into()),
value: Some(value.into()),
metadata_id: Some(self.meta_id),
});
}
}
}