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::events::GraphObjectEventTracker;
6use super::types::{EdgeMarker, VertexId};
7use super::{EdgeGraphMetadata, Metadata, Vertex};
8use fuchsia_inspect as inspect;
9use fuchsia_sync::{RwLock, RwLockWriteGuard};
10use std::ops::{Deref, DerefMut};
11use std::sync::atomic::{AtomicU64, Ordering};
12use std::sync::{Arc, Weak};
13
14/// An Edge in the graph.
15#[derive(Debug)]
16pub struct Edge {
17    state: Arc<RwLock<EdgeState>>,
18}
19
20static NEXT_ID: AtomicU64 = AtomicU64::new(0);
21
22impl Edge {
23    pub(crate) fn new<'a, I, M>(
24        from: &Vertex<I>,
25        to: &mut Vertex<I>,
26        initial_metadata: M,
27        events_tracker: Option<GraphObjectEventTracker<EdgeMarker>>,
28    ) -> Self
29    where
30        I: VertexId,
31        M: IntoIterator<Item = Metadata<'a>>,
32    {
33        let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
34        let to_id = to.id().get_id();
35        let metadata_iterator = initial_metadata.into_iter();
36        let (node, metadata) = from.outgoing_edges_node.atomic_update(|parent| {
37            let node = parent.create_child(to_id.as_ref());
38            node.record_uint("edge_id", id);
39            let metadata = EdgeGraphMetadata::new(
40                &node,
41                id,
42                metadata_iterator,
43                events_tracker,
44                from.id().get_id().as_ref(),
45                to_id.as_ref(),
46            );
47            (node, metadata)
48        });
49        let state = Arc::new(RwLock::new(EdgeState::Active { metadata, _node: node }));
50        Self { state }
51    }
52
53    /// Get an exclusive reference to the metadata to modify it.
54    pub fn meta(&mut self) -> EdgeGraphMetadataRef<'_> {
55        let lock = self.state.write();
56        EdgeGraphMetadataRef { lock }
57    }
58
59    pub(crate) fn id(&self) -> u64 {
60        self.state.read().metadata().id()
61    }
62
63    pub(crate) fn weak_ref(&self) -> WeakEdgeRef {
64        WeakEdgeRef(Arc::downgrade(&self.state))
65    }
66}
67
68pub struct EdgeGraphMetadataRef<'a> {
69    lock: RwLockWriteGuard<'a, EdgeState>,
70}
71
72impl Deref for EdgeGraphMetadataRef<'_> {
73    type Target = EdgeGraphMetadata;
74
75    fn deref(&self) -> &Self::Target {
76        self.lock.metadata()
77    }
78}
79
80impl DerefMut for EdgeGraphMetadataRef<'_> {
81    fn deref_mut(&mut self) -> &mut Self::Target {
82        self.lock.metadata_mut()
83    }
84}
85
86#[derive(Debug)]
87enum EdgeState {
88    Active { metadata: EdgeGraphMetadata, _node: inspect::Node },
89    Gone { metadata: EdgeGraphMetadata },
90}
91
92impl EdgeState {
93    pub fn mark_as_gone(&mut self) {
94        match self {
95            Self::Active { metadata, .. } => {
96                let id = metadata.id();
97                *self = Self::Gone { metadata: EdgeGraphMetadata::noop(id) };
98            }
99            Self::Gone { .. } => {}
100        }
101    }
102
103    fn metadata_mut(&mut self) -> &mut EdgeGraphMetadata {
104        match self {
105            EdgeState::Active { metadata, .. } | EdgeState::Gone { metadata, .. } => metadata,
106        }
107    }
108
109    fn metadata(&self) -> &EdgeGraphMetadata {
110        match self {
111            EdgeState::Active { metadata, .. } | EdgeState::Gone { metadata, .. } => metadata,
112        }
113    }
114}
115
116#[derive(Debug, Clone)]
117pub(crate) struct WeakEdgeRef(Weak<RwLock<EdgeState>>);
118
119impl WeakEdgeRef {
120    pub fn mark_as_gone(&self) {
121        if let Some(value) = self.0.upgrade() {
122            value.write().mark_as_gone();
123        }
124    }
125
126    pub fn is_valid(&self) -> bool {
127        self.0.upgrade().map(|v| matches!(*v.read(), EdgeState::Active { .. })).unwrap_or(false)
128    }
129}
130
131impl Drop for Edge {
132    fn drop(&mut self) {
133        if let Some(events_tracker) = self.state.read().metadata().events_tracker() {
134            events_tracker.record_removed(self.id());
135        }
136    }
137}