standing_relations/core/context/
tracking.rs

1use std::{
2    fmt::{self, Debug, Display},
3    io::{self, Write},
4    sync::{Arc, RwLock},
5};
6
7use crate::core::{
8    dirty::ReceiveBuilder,
9    pipes::{self, CountReceiver},
10    relation::RelationInner,
11    Op_, Relation,
12};
13
14#[derive(Clone, Copy)]
15pub struct TrackingIndex(usize);
16
17impl TrackingIndex {
18    fn new(i: usize) -> Self {
19        TrackingIndex(i)
20    }
21}
22
23impl Display for TrackingIndex {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        Display::fmt(&self.0, f)
26    }
27}
28
29#[derive(Clone, Default)]
30pub struct ContextTracker(Arc<RwLock<ContextTrackerInner>>);
31struct TrackingInfo {
32    name: String,
33    type_name: String,
34    hidden: bool,
35    count: CountReceiver,
36    deps: Vec<TrackingIndex>,
37}
38
39#[derive(Default)]
40struct ContextTrackerInner(Vec<TrackingInfo>);
41
42impl PartialEq for ContextTracker {
43    fn eq(&self, other: &Self) -> bool {
44        Arc::ptr_eq(&self.0, &other.0)
45    }
46}
47impl Eq for ContextTracker {}
48impl ContextTracker {
49    pub(in crate::core) fn add_relation<C: Op_>(
50        self,
51        dirty: ReceiveBuilder,
52        inner: C,
53        deps: Vec<TrackingIndex>,
54    ) -> Relation<C> {
55        let (count_send, count_receive) = pipes::new_count();
56        let tracking_index = TrackingIndex::new(self.0.read().unwrap().0.len());
57        self.0.write().unwrap().0.push(TrackingInfo {
58            name: format!("relation{}", tracking_index),
59            type_name: C::get_type_name().to_string(),
60            hidden: false,
61            count: count_receive,
62            deps,
63        });
64        Relation {
65            context_tracker: self,
66            shown_index: tracking_index,
67            tracking_index,
68            dirty,
69            inner: RelationInner::new(inner, count_send),
70        }
71    }
72    pub fn dump_dot(
73        &self,
74        file: impl Write,
75        extra_edges: &[(TrackingIndex, TrackingIndex)],
76    ) -> Result<(), io::Error> {
77        self.0.read().unwrap().dump_dot(file, extra_edges)
78    }
79
80    pub(crate) fn set_name(&mut self, index: TrackingIndex, name: String) {
81        self.0.write().unwrap().set_name(index, name)
82    }
83
84    pub(crate) fn set_type_name(&mut self, index: TrackingIndex, type_name: String) {
85        self.0.write().unwrap().set_type_name(index, type_name)
86    }
87
88    pub(crate) fn set_hidden(&mut self, index: TrackingIndex) {
89        self.0.write().unwrap().set_hidden(index)
90    }
91
92    pub(crate) fn find_shown_index(&self, index: TrackingIndex) -> TrackingIndex {
93        self.0.read().unwrap().find_shown_index(index)
94    }
95}
96impl Debug for ContextTracker {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        write!(f, "{:?}", Arc::as_ptr(&self.0))
99    }
100}
101
102impl ContextTrackerInner {
103    fn find_shown_index(&self, mut ind: TrackingIndex) -> TrackingIndex {
104        loop {
105            let t = &self.0[ind.0];
106            if t.hidden {
107                assert_eq!(
108                    t.deps.len(),
109                    1,
110                    "unreachable; hidden node with non-one deps"
111                );
112                ind = t.deps[0];
113            } else {
114                return ind;
115            }
116        }
117    }
118    fn dump_dot(
119        &self,
120        mut file: impl Write,
121        extra_edges: &[(TrackingIndex, TrackingIndex)],
122    ) -> Result<(), io::Error> {
123        writeln!(file, "digraph flow {{")?;
124        for (i, info) in self.0.iter().enumerate() {
125            if info.hidden {
126                continue;
127            }
128            let name = format!("{} <br/>", info.name);
129            writeln!(
130                file,
131                "  node{} [label=< {} {} <br/> {} >];",
132                i,
133                name,
134                info.type_name,
135                info.count.get()
136            )?;
137            for &dep in info.deps.iter() {
138                writeln!(file, "  node{} -> node{};", self.find_shown_index(dep), i)?;
139            }
140        }
141        for &(i, j) in extra_edges {
142            writeln!(
143                file,
144                "  node{} -> node{} [style=dotted];",
145                self.find_shown_index(i),
146                self.find_shown_index(j)
147            )?;
148        }
149        writeln!(file, "}}")
150    }
151    pub fn set_name(&mut self, index: TrackingIndex, name: String) {
152        self.0[index.0].name = name
153    }
154    pub fn set_type_name(&mut self, index: TrackingIndex, type_name: String) {
155        self.0[index.0].type_name = type_name
156    }
157    pub fn set_hidden(&mut self, index: TrackingIndex) {
158        let mut info = &mut self.0[index.0];
159        assert_eq!(
160            info.deps.len(),
161            1,
162            "Can only hide nodes with exactly one dependency"
163        );
164        info.hidden = true;
165    }
166}