fuchsia_inspect_contrib/graph/
edge.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::types::VertexId;
6use super::{Vertex, VertexMetadata};
7use fuchsia_inspect as inspect;
8use fuchsia_sync::RwLock;
9use std::sync::atomic::{AtomicU64, Ordering};
10use std::sync::{Arc, Weak};
11
12/// An Edge in the graph.
13#[derive(Debug)]
14pub struct Edge<EM> {
15    state: Arc<RwLock<EdgeState<EM>>>,
16    id: u64,
17}
18
19static NEXT_ID: AtomicU64 = AtomicU64::new(0);
20
21pub trait EdgeMetadata {}
22
23impl<EM> Edge<EM> {
24    pub(crate) fn new<VM>(
25        from: &Vertex<VM>,
26        to: &mut Vertex<VM>,
27        init_metadata: impl FnOnce(inspect::Node) -> EM,
28    ) -> Self
29    where
30        VM: VertexMetadata<EdgeMeta = EM>,
31    {
32        let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
33        let to_id = to.id().get_id();
34        let (node, metadata) = from.outgoing_edges_node.atomic_update(|parent| {
35            let node = parent.create_child(to_id.as_ref());
36            node.record_uint("edge_id", id);
37            let metadata = init_metadata(node.create_child("meta"));
38            (node, metadata)
39        });
40        let state = Arc::new(RwLock::new(EdgeState::Active { metadata, _node: node }));
41        Self { state, id }
42    }
43
44    pub fn maybe_update_meta(&self, cb: impl FnOnce(&mut EM)) {
45        let mut lock = self.state.write();
46        if let Some(meta) = lock.metadata_mut() {
47            cb(meta);
48        }
49    }
50
51    pub fn id(&self) -> u64 {
52        self.id
53    }
54
55    pub(crate) fn weak_ref(&self) -> WeakEdgeRef<EM> {
56        WeakEdgeRef(Arc::downgrade(&self.state))
57    }
58}
59
60#[derive(Debug)]
61enum EdgeState<EM> {
62    Active { metadata: EM, _node: inspect::Node },
63    Gone,
64}
65
66impl<EM> EdgeState<EM> {
67    pub fn mark_as_gone(&mut self) {
68        match self {
69            Self::Active { .. } => *self = Self::Gone,
70            Self::Gone { .. } => {}
71        }
72    }
73
74    fn metadata_mut(&mut self) -> Option<&mut EM> {
75        match self {
76            EdgeState::Active { metadata, .. } => Some(metadata),
77            EdgeState::Gone => None,
78        }
79    }
80}
81
82#[derive(Debug)]
83pub(crate) struct WeakEdgeRef<EM>(Weak<RwLock<EdgeState<EM>>>);
84
85impl<EM> Clone for WeakEdgeRef<EM> {
86    fn clone(&self) -> Self {
87        Self(self.0.clone())
88    }
89}
90
91impl<EM> WeakEdgeRef<EM> {
92    pub fn mark_as_gone(&self) {
93        if let Some(value) = self.0.upgrade() {
94            value.write().mark_as_gone();
95        }
96    }
97
98    pub fn is_valid(&self) -> bool {
99        self.0.upgrade().map(|v| matches!(*v.read(), EdgeState::Active { .. })).unwrap_or(false)
100    }
101}