depends/execution/
identifiable.rs

1use std::{
2    rc::Rc,
3    sync::atomic::{AtomicUsize, Ordering},
4};
5
6use super::Named;
7
8/// Global node Ids are kept in order to track execution across graphs.
9static NODE_ID: AtomicUsize = AtomicUsize::new(0);
10
11/// Public interface to the global [NODE_ID].
12#[doc(hidden)]
13pub fn next_node_id() -> usize {
14    NODE_ID.fetch_add(1, Ordering::Relaxed)
15}
16
17#[cfg(test)]
18pub fn reset_node_id() {
19    NODE_ID.store(0, Ordering::Relaxed);
20}
21
22/// Put this behind unsafe so that tests outside of this crate can reset the
23/// node id.
24///
25/// This is unsafe to call because it will affect the node count to other
26/// co-existing graphs. Make sure you're running this test in `serial`.
27///
28/// # Safety
29///
30/// Only for use in testing.
31#[allow(unused)]
32pub unsafe fn ext_reset_node_id() {
33    NODE_ID.store(0, Ordering::Relaxed);
34}
35
36/// A unique integer value assigned to each node created in a particular
37/// runtime, allowing a [Visitor](super::Visitor) to track visited nodes when
38/// resolving graphs.
39pub trait Identifiable: Named {
40    fn id(&self) -> usize;
41}
42
43impl<T> Identifiable for Rc<T>
44where
45    T: Identifiable,
46{
47    fn id(&self) -> usize {
48        T::id(self)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use serial_test::serial;
55
56    use super::*;
57    use crate::execution::{internal_test_utils::TestData, InputNode};
58
59    #[test]
60    #[serial]
61    fn test_identifiable_rc() {
62        reset_node_id();
63        for i in 0..32 {
64            let node = InputNode::new(TestData::new(i));
65            let rc = Rc::new(node);
66            assert_eq!(rc.id(), i as usize);
67        }
68    }
69
70    #[test]
71    #[serial]
72    fn test_next_node_id() {
73        reset_node_id();
74        for i in 0..32_usize {
75            assert_eq!(next_node_id(), i);
76        }
77    }
78}