standing_relations/core/context/
tracking.rs1use 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}