fuchsia_inspect_contrib/graph/
vertex.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::edge::WeakEdgeRef;
6use super::events::GraphObjectEventTracker;
7use super::types::VertexMarker;
8use super::{Edge, Metadata, VertexGraphMetadata, VertexId};
9use fuchsia_inspect as inspect;
10use std::collections::BTreeMap;
11use std::sync::atomic::{AtomicU64, Ordering};
12
13/// A vertex of the graph. When this is dropped, all the outgoing edges and metadata fields will
14/// removed from Inspect.
15#[derive(Debug)]
16pub struct Vertex<I: VertexId> {
17    _node: inspect::Node,
18    metadata: VertexGraphMetadata<I>,
19    incoming_edges: BTreeMap<u64, WeakEdgeRef>,
20    outgoing_edges: BTreeMap<u64, WeakEdgeRef>,
21    pub(crate) outgoing_edges_node: inspect::Node,
22    internal_id: u64,
23}
24
25static NEXT_ID: AtomicU64 = AtomicU64::new(0);
26
27impl<I> Vertex<I>
28where
29    I: VertexId,
30{
31    pub(crate) fn new<'a, M>(
32        id: I,
33        parent: &inspect::Node,
34        initial_metadata: M,
35        events_tracker: Option<GraphObjectEventTracker<VertexMarker<I>>>,
36    ) -> Self
37    where
38        M: IntoIterator<Item = Metadata<'a>>,
39    {
40        let internal_id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
41        let metadata_iterator = initial_metadata.into_iter();
42        parent.atomic_update(|parent| {
43            let id_str = id.get_id();
44            let node = parent.create_child(id_str.as_ref());
45            let outgoing_edges_node = node.create_child("relationships");
46            let metadata = VertexGraphMetadata::new(&node, id, metadata_iterator, events_tracker);
47            Vertex {
48                internal_id,
49                _node: node,
50                outgoing_edges_node,
51                metadata,
52                incoming_edges: BTreeMap::new(),
53                outgoing_edges: BTreeMap::new(),
54            }
55        })
56    }
57
58    /// Add a new edge to the graph originating at this vertex and going to the vertex `to` with the
59    /// given metadata.
60    pub fn add_edge<'a, M>(&mut self, to: &mut Vertex<I>, initial_metadata: M) -> Edge
61    where
62        M: IntoIterator<Item = Metadata<'a>>,
63    {
64        let edge = Edge::new(
65            self,
66            to,
67            initial_metadata,
68            self.metadata.events_tracker().map(|e| e.for_edge()),
69        );
70
71        let weak_ref = edge.weak_ref();
72
73        self.incoming_edges.retain(|_, n| n.is_valid());
74        to.outgoing_edges.retain(|_, n| n.is_valid());
75
76        to.incoming_edges.insert(self.internal_id, weak_ref.clone());
77        self.outgoing_edges.insert(to.internal_id, weak_ref);
78        edge
79    }
80
81    /// Get an exclusive reference to the metadata to modify it.
82    pub fn meta(&mut self) -> &mut VertexGraphMetadata<I> {
83        &mut self.metadata
84    }
85
86    pub(crate) fn id(&self) -> &I {
87        self.metadata.id()
88    }
89}
90
91impl<I> Drop for Vertex<I>
92where
93    I: VertexId,
94{
95    fn drop(&mut self) {
96        self.outgoing_edges.iter().for_each(|(_, n)| n.mark_as_gone());
97        self.incoming_edges.iter().for_each(|(_, n)| n.mark_as_gone());
98        if let Some(events_tracker) = self.metadata.events_tracker() {
99            events_tracker.record_removed(self.id().get_id().as_ref())
100        }
101    }
102}