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::{Edge, EdgeMetadata, VertexId};
7use fuchsia_inspect as inspect;
8use std::collections::BTreeMap;
9use std::sync::atomic::{AtomicU64, Ordering};
10
11/// A vertex of the graph. When this is dropped, all the outgoing edges and metadata fields will
12/// removed from Inspect.
13#[derive(Debug)]
14pub struct Vertex<M: VertexMetadata> {
15    _node: inspect::Node,
16    id: M::Id,
17    metadata: M,
18    incoming_edges: BTreeMap<u64, WeakEdgeRef<M::EdgeMeta>>,
19    outgoing_edges: BTreeMap<u64, WeakEdgeRef<M::EdgeMeta>>,
20    pub(crate) outgoing_edges_node: inspect::Node,
21    internal_id: u64,
22}
23
24/// Trait implemented by types that hold a vertex metadata.
25pub trait VertexMetadata {
26    type Id: VertexId;
27    type EdgeMeta: EdgeMetadata;
28}
29
30static NEXT_ID: AtomicU64 = AtomicU64::new(0);
31
32impl<M: VertexMetadata> Vertex<M>
33where
34    <M as VertexMetadata>::Id: VertexId,
35{
36    pub(crate) fn new(
37        id: M::Id,
38        parent: &inspect::Node,
39        init_metadata: impl FnOnce(inspect::Node) -> M,
40    ) -> Self {
41        let internal_id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
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 = init_metadata(node.create_child("meta"));
47            Vertex {
48                id,
49                internal_id,
50                _node: node,
51                outgoing_edges_node,
52                metadata,
53                incoming_edges: BTreeMap::new(),
54                outgoing_edges: BTreeMap::new(),
55            }
56        })
57    }
58
59    /// Add a new edge to the graph originating at this vertex and going to the vertex `to` with the
60    /// given metadata.
61    pub fn add_edge(
62        &mut self,
63        to: &mut Vertex<M>,
64        init_metadata: impl FnOnce(inspect::Node) -> M::EdgeMeta,
65    ) -> Edge<M::EdgeMeta> {
66        let edge = Edge::new(self, to, init_metadata);
67
68        let weak_ref = edge.weak_ref();
69
70        self.incoming_edges.retain(|_, n| n.is_valid());
71        to.outgoing_edges.retain(|_, n| n.is_valid());
72
73        to.incoming_edges.insert(self.internal_id, weak_ref.clone());
74        self.outgoing_edges.insert(to.internal_id, weak_ref);
75        edge
76    }
77
78    /// Get an exclusive reference to the metadata to modify it.
79    pub fn meta(&mut self) -> &mut M {
80        &mut self.metadata
81    }
82
83    pub(crate) fn id(&self) -> &M::Id {
84        &self.id
85    }
86}
87
88impl<M> Drop for Vertex<M>
89where
90    M: VertexMetadata,
91{
92    fn drop(&mut self) {
93        self.outgoing_edges.iter().for_each(|(_, n)| n.mark_as_gone());
94        self.incoming_edges.iter().for_each(|(_, n)| n.mark_as_gone());
95    }
96}