1use super::events::{GraphObjectEventTracker, MetaEventNode};
6use super::types::{EdgeMarker, GraphObject, VertexMarker};
7use super::VertexId;
8use fuchsia_inspect::{self as inspect, ArrayProperty, Property};
9use std::borrow::Cow;
10use std::collections::BTreeMap;
11use std::ops::Deref;
12
13#[derive(Debug)]
15pub enum MetadataValue<'a> {
16 Int(i64),
17 Uint(u64),
18 Double(f64),
19 Str(Cow<'a, str>),
20 Bool(bool),
21 IntVec(Vec<i64>),
22 UintVec(Vec<u64>),
23 DoubleVec(Vec<f64>),
24}
25
26impl MetadataValue<'_> {
27 pub(crate) fn record_inspect(&self, node: &inspect::Node, key: &str) {
28 match self {
29 Self::Int(value) => node.record_int(key, *value),
30 Self::Uint(value) => node.record_uint(key, *value),
31 Self::Double(value) => node.record_double(key, *value),
32 Self::Str(value) => node.record_string(key, value.as_ref()),
33 Self::Bool(value) => node.record_bool(key, *value),
34 Self::IntVec(value) => {
35 node.atomic_update(|node| {
36 let prop = node.create_int_array(key, value.len());
37 for (idx, v) in value.iter().enumerate() {
38 prop.set(idx, *v);
39 }
40 node.record(prop);
41 });
42 }
43 Self::UintVec(value) => {
44 node.atomic_update(|node| {
45 let prop = node.create_uint_array(key, value.len());
46 for (idx, v) in value.iter().enumerate() {
47 prop.set(idx, *v);
48 }
49 node.record(prop);
50 });
51 }
52 Self::DoubleVec(value) => {
53 node.atomic_update(|node| {
54 let prop = node.create_double_array(key, value.len());
55 for (idx, v) in value.iter().enumerate() {
56 prop.set(idx, *v);
57 }
58 node.record(prop);
59 });
60 }
61 }
62 }
63}
64
65impl<'a, T> From<&'a T> for MetadataValue<'a>
66where
67 T: VertexId,
68{
69 fn from(value: &'a T) -> MetadataValue<'a> {
70 Self::Str(value.get_id())
71 }
72}
73
74macro_rules! impl_from_for_metadata_value {
75 ($([($($type:ty),*), $name:ident, $cast_type:ty]),*) => {
76 $($(
77 impl From<$type> for MetadataValue<'_> {
78 fn from(value: $type) -> MetadataValue<'static> {
79 MetadataValue::$name(value as $cast_type)
80 }
81 }
82 )*)*
83 };
84}
85
86impl_from_for_metadata_value!(
87 [(i8, i16, i32, i64), Int, i64],
88 [(u8, u16, u32, u64), Uint, u64],
89 [(f32, f64), Double, f64]
90);
91
92impl From<bool> for MetadataValue<'_> {
93 fn from(value: bool) -> MetadataValue<'static> {
94 MetadataValue::Bool(value)
95 }
96}
97
98impl<'a> From<&'a str> for MetadataValue<'a> {
99 fn from(value: &'a str) -> MetadataValue<'a> {
100 MetadataValue::Str(Cow::Borrowed(value))
101 }
102}
103
104impl From<String> for MetadataValue<'_> {
105 fn from(value: String) -> MetadataValue<'static> {
106 MetadataValue::Str(Cow::Owned(value))
107 }
108}
109
110impl<'a> From<Cow<'a, str>> for MetadataValue<'a> {
111 fn from(value: Cow<'a, str>) -> MetadataValue<'a> {
112 MetadataValue::Str(value)
113 }
114}
115
116impl<'a> From<Vec<i64>> for MetadataValue<'a> {
117 fn from(value: Vec<i64>) -> MetadataValue<'a> {
118 MetadataValue::IntVec(value)
119 }
120}
121
122impl<'a> From<Vec<u8>> for MetadataValue<'a> {
123 fn from(value: Vec<u8>) -> MetadataValue<'a> {
124 MetadataValue::UintVec(value.into_iter().map(|v| v as u64).collect())
125 }
126}
127
128impl<'a> From<Vec<u64>> for MetadataValue<'a> {
129 fn from(value: Vec<u64>) -> MetadataValue<'a> {
130 MetadataValue::UintVec(value)
131 }
132}
133
134impl<'a> From<Vec<f64>> for MetadataValue<'a> {
135 fn from(value: Vec<f64>) -> MetadataValue<'a> {
136 MetadataValue::DoubleVec(value)
137 }
138}
139
140pub struct Metadata<'a> {
142 pub(crate) key: Cow<'a, str>,
144 inner: InnerMetadata<'a>,
146}
147
148impl<'a> Metadata<'a> {
149 pub fn new(key: impl Into<Cow<'a, str>>, value: impl Into<MetadataValue<'a>>) -> Self {
151 Self {
152 key: key.into(),
153 inner: InnerMetadata::Value { value: value.into(), track_events: false },
154 }
155 }
156
157 pub fn nested(
158 key: impl Into<Cow<'a, str>>,
159 value: impl IntoIterator<Item = Metadata<'a>> + 'a,
160 ) -> Self {
161 Self { key: key.into(), inner: InnerMetadata::Nested(Box::new(value.into_iter())) }
162 }
163
164 pub fn track_events(mut self) -> Self {
168 match &mut self.inner {
169 InnerMetadata::Value { ref mut track_events, .. } => *track_events = true,
170 InnerMetadata::Nested(_) => {}
171 }
172 self
173 }
174}
175
176enum InnerMetadata<'a> {
177 Value {
178 value: MetadataValue<'a>,
179 track_events: bool,
181 },
182 Nested(Box<dyn Iterator<Item = Metadata<'a>> + 'a>),
183}
184
185#[derive(Debug)]
186pub struct VertexGraphMetadata<I>
187where
188 I: VertexId,
189{
190 inner: GraphMetadata<VertexMarker<I>>,
191}
192
193impl<I: VertexId> VertexGraphMetadata<I> {
194 pub fn set<'a, 'b>(
197 &mut self,
198 key: impl Into<Cow<'a, str>>,
199 value: impl Into<MetadataValue<'b>>,
200 ) {
201 self.inner.set(key, value, None);
202 }
203
204 pub fn set_and_track<'a, 'b>(
205 &mut self,
206 key: impl Into<Cow<'a, str>>,
207 value: impl Into<MetadataValue<'b>>,
208 ) {
209 self.inner.set(key, value, Some(true));
210 }
211
212 pub fn remove(&mut self, key: &str) {
214 self.inner.remove(key);
215 }
216
217 pub fn remove_and_track(&mut self, key: &str) {
218 self.inner.remove_and_track(key);
219 }
220
221 pub(crate) fn new<'a>(
222 parent: &inspect::Node,
223 id: I,
224 initial_metadata: impl Iterator<Item = Metadata<'a>>,
225 events_tracker: Option<GraphObjectEventTracker<VertexMarker<I>>>,
226 ) -> Self {
227 let (inner, meta_event_node) =
228 GraphMetadata::new(parent, id, initial_metadata, events_tracker);
229 if let Some(ref events_tracker) = inner.events_tracker {
230 events_tracker.record_added(&inner.id, meta_event_node);
231 }
232 Self { inner }
233 }
234
235 pub(crate) fn events_tracker(&self) -> Option<&GraphObjectEventTracker<VertexMarker<I>>> {
236 self.inner.events_tracker.as_ref()
237 }
238
239 pub(crate) fn id(&self) -> &I {
240 &self.inner.id
241 }
242}
243
244#[derive(Debug)]
245pub struct EdgeGraphMetadata {
246 inner: GraphMetadata<EdgeMarker>,
247}
248
249impl EdgeGraphMetadata {
250 pub fn set<'a, 'b>(
253 &mut self,
254 key: impl Into<Cow<'a, str>>,
255 value: impl Into<MetadataValue<'b>>,
256 ) {
257 self.inner.set(key, value, None);
258 }
259
260 pub fn remove(&mut self, key: &str) {
262 self.inner.remove(key);
263 }
264
265 pub(crate) fn new<'a>(
266 parent: &inspect::Node,
267 id: u64,
268 initial_metadata: impl Iterator<Item = Metadata<'a>>,
269 events_tracker: Option<GraphObjectEventTracker<EdgeMarker>>,
270 from_id: &str,
271 to_id: &str,
272 ) -> Self {
273 let (inner, meta_event_node) =
274 GraphMetadata::new(parent, id, initial_metadata, events_tracker);
275 if let Some(ref events_tracker) = inner.events_tracker {
276 events_tracker.record_added(from_id, to_id, id, meta_event_node);
277 }
278 Self { inner }
279 }
280
281 pub(crate) fn events_tracker(&self) -> Option<&GraphObjectEventTracker<EdgeMarker>> {
282 self.inner.events_tracker.as_ref()
283 }
284
285 pub(crate) fn id(&self) -> u64 {
286 self.inner.id
287 }
288
289 pub(crate) fn noop(id: <EdgeMarker as GraphObject>::Id) -> EdgeGraphMetadata {
290 Self {
291 inner: GraphMetadata {
292 id,
293 map: BTreeMap::default(),
294 events_tracker: None,
295 node: inspect::Node::default(),
296 },
297 }
298 }
299}
300
301#[derive(Debug)]
302#[allow(dead_code)] enum MetadataProperty {
304 Int(inspect::IntProperty),
305 Uint(inspect::UintProperty),
306 Double(inspect::DoubleProperty),
307 Str(inspect::StringProperty),
308 Bool(inspect::BoolProperty),
309 IntVec(inspect::IntArrayProperty),
310 UintVec(inspect::UintArrayProperty),
311 DoubleVec(inspect::DoubleArrayProperty),
312}
313
314#[derive(Debug)]
316struct GraphMetadata<T: GraphObject> {
317 id: T::Id,
318 map: BTreeMap<String, (MetadataProperty, bool)>,
319 events_tracker: Option<GraphObjectEventTracker<T>>,
320 node: inspect::Node,
321}
322
323impl<T> GraphMetadata<T>
324where
325 T: GraphObject,
326{
327 fn new<'a>(
328 parent: &inspect::Node,
329 id: T::Id,
330 initial_metadata: impl Iterator<Item = Metadata<'a>>,
331 events_tracker: Option<GraphObjectEventTracker<T>>,
332 ) -> (Self, MetaEventNode) {
333 let node = parent.create_child("meta");
334 let meta_event_node = MetaEventNode::new(parent);
335
336 let mut map = BTreeMap::default();
337 node.atomic_update(|node| {
338 for Metadata { key, inner } in initial_metadata.into_iter() {
339 match inner {
340 InnerMetadata::Nested(_) => {
341 Self::insert_nested_to_map(
342 node,
343 meta_event_node.deref(),
344 &mut vec![],
345 &mut map,
346 Metadata { key, inner },
347 );
348 }
349 InnerMetadata::Value { value, track_events } => {
350 let key = key.to_string();
351 if events_tracker.is_some() && track_events {
352 value.record_inspect(&meta_event_node, &key);
353 }
354 Self::insert_to_map(node, &mut map, &[key.into()], value, track_events)
355 }
356 }
357 }
358 });
359 (Self { id, node, map, events_tracker }, meta_event_node)
360 }
361
362 fn set<'a, 'b>(
363 &mut self,
364 key: impl Into<Cow<'a, str>>,
365 value: impl Into<MetadataValue<'b>>,
366 maybe_track: Option<bool>,
367 ) {
368 let key: Cow<'a, str> = key.into();
369 if let Some(choice) = maybe_track {
371 if let Some((_, ref mut track_events)) = self.map.get_mut(key.as_ref()) {
372 if *track_events != choice {
373 *track_events = choice;
374 }
375 }
376 }
377 let value = value.into();
378
379 log::debug!("trying to set key={:?} to value={:?}", &key, &value);
381 match (self.map.get(key.as_ref()), value) {
382 (
383 Some((MetadataProperty::Int(property), track_events)),
384 value @ MetadataValue::Int(x),
385 ) => {
386 property.set(x);
387 if *track_events {
388 self.log_update_key(key.as_ref(), &value)
389 }
390 }
391 (
392 Some((MetadataProperty::Uint(property), track_events)),
393 value @ MetadataValue::Uint(x),
394 ) => {
395 property.set(x);
396 if *track_events {
397 self.log_update_key(key.as_ref(), &value)
398 }
399 }
400 (
401 Some((MetadataProperty::Double(property), track_events)),
402 value @ MetadataValue::Double(x),
403 ) => {
404 property.set(x);
405 if *track_events {
406 self.log_update_key(key.as_ref(), &value)
407 }
408 }
409 (
410 Some((MetadataProperty::Bool(property), track_events)),
411 value @ MetadataValue::Bool(x),
412 ) => {
413 property.set(x);
414 if *track_events {
415 self.log_update_key(key.as_ref(), &value)
416 }
417 }
418 (
419 Some((MetadataProperty::Str(property), track_events)),
420 ref value @ MetadataValue::Str(ref x),
421 ) => {
422 property.set(x);
423 if *track_events {
424 self.log_update_key(key.as_ref(), value)
425 }
426 }
427 (Some((MetadataProperty::IntVec(_), _)), MetadataValue::IntVec(_)) => {
428 }
430 (Some((MetadataProperty::UintVec(_), _)), MetadataValue::UintVec(_)) => {
431 }
433 (Some((MetadataProperty::DoubleVec(_), _)), MetadataValue::DoubleVec(_)) => {
434 }
436 (Some((_, track_events)), value) => {
437 let track_events = *track_events; if track_events {
439 self.log_update_key(key.as_ref(), &value)
440 }
441 Self::insert_to_map(&self.node, &mut self.map, &[key], value, track_events);
442 }
443 (None, value) => {
444 let track_events = maybe_track.unwrap_or(false);
445 if track_events {
446 self.log_update_key(key.as_ref(), &value)
447 }
448 Self::insert_to_map(&self.node, &mut self.map, &[key], value, track_events);
449 }
450 }
451 }
452
453 fn remove(&mut self, key: &str) {
454 self.map.remove(key);
455 }
456
457 fn remove_and_track(&mut self, key: &str) {
458 if self.map.remove(key).is_some() {
459 if let Some(events_tracker) = &self.events_tracker {
460 events_tracker.metadata_dropped(&self.id, key);
461 }
462 }
463 }
464
465 fn log_update_key(&self, key: &str, value: &MetadataValue<'_>) {
466 if let Some(events_tracker) = &self.events_tracker {
467 events_tracker.metadata_updated(&self.id, key, value);
468 }
469 }
470
471 fn insert_to_map(
472 node: &inspect::Node,
473 map: &mut BTreeMap<String, (MetadataProperty, bool)>,
474 key_path: &[Cow<'_, str>],
475 value: MetadataValue<'_>,
476 track_events: bool,
477 ) {
478 let node_key = key_path.last().unwrap().as_ref();
479 let map_key = key_path.join("/");
480 match value {
481 MetadataValue::Int(value) => {
482 let property = node.create_int(node_key, value);
483 map.insert(map_key, (MetadataProperty::Int(property), track_events));
484 }
485 MetadataValue::Uint(value) => {
486 let property = node.create_uint(node_key, value);
487 map.insert(map_key, (MetadataProperty::Uint(property), track_events));
488 }
489 MetadataValue::Double(value) => {
490 let property = node.create_double(node_key, value);
491 map.insert(map_key, (MetadataProperty::Double(property), track_events));
492 }
493 MetadataValue::Str(value) => {
494 let property = node.create_string(node_key, value);
495 map.insert(map_key, (MetadataProperty::Str(property), track_events));
496 }
497 MetadataValue::Bool(value) => {
498 let property = node.create_bool(node_key, value);
499 map.insert(map_key, (MetadataProperty::Bool(property), track_events));
500 }
501 MetadataValue::IntVec(value) => {
502 let property = node.atomic_update(|node| {
503 let property = node.create_int_array(node_key, value.len());
504 for (idx, v) in value.into_iter().enumerate() {
505 property.set(idx, v);
506 }
507 property
508 });
509 map.insert(map_key, (MetadataProperty::IntVec(property), track_events));
510 }
511 MetadataValue::UintVec(value) => {
512 let property = node.atomic_update(|node| {
513 let property = node.create_uint_array(node_key, value.len());
514 for (idx, v) in value.into_iter().enumerate() {
515 property.set(idx, v);
516 }
517 property
518 });
519 map.insert(map_key, (MetadataProperty::UintVec(property), track_events));
520 }
521 MetadataValue::DoubleVec(value) => {
522 let property = node.atomic_update(|node| {
523 let property = node.create_double_array(node_key, value.len());
524 for (idx, v) in value.into_iter().enumerate() {
525 property.set(idx, v);
526 }
527 property
528 });
529 map.insert(map_key, (MetadataProperty::DoubleVec(property), track_events));
530 }
531 }
532 }
533
534 fn insert_nested_to_map<'a>(
535 parent: &inspect::Node,
536 parent_event_node: &inspect::Node,
537 key_path: &mut Vec<Cow<'a, str>>,
538 map: &mut BTreeMap<String, (MetadataProperty, bool)>,
539 metadata: Metadata<'a>,
540 ) -> bool {
541 let Metadata { key, inner: InnerMetadata::Nested(children) } = metadata else {
542 unreachable!("We can only reach this function with nested nodes.");
543 };
544 let meta_node = parent.create_child(key.as_ref());
545 let event_node = parent_event_node.create_child(key.as_ref());
546
547 key_path.push(key);
548
549 let mut recorded_events = false;
550 for Metadata { inner: child_inner, key: child_key } in children {
551 match child_inner {
552 InnerMetadata::Nested(_) => {
553 recorded_events |= Self::insert_nested_to_map(
554 &meta_node,
555 &event_node,
556 key_path,
557 map,
558 Metadata { inner: child_inner, key: child_key },
559 );
560 }
561 InnerMetadata::Value { value, track_events } => {
562 if track_events {
563 recorded_events = true;
564 value.record_inspect(&event_node, &child_key);
565 }
566 key_path.push(child_key);
567 Self::insert_to_map(&meta_node, map, key_path, value, track_events);
568 key_path.pop();
569 }
570 }
571 }
572
573 key_path.pop();
574
575 parent.record(meta_node);
578 if recorded_events {
579 parent_event_node.record(event_node);
580 }
581
582 recorded_events
583 }
584}