1use fabula::datasource::{DataSource, Edge, ValueConstraint};
7use fabula::interval::Interval;
8use std::fmt;
9use std::hash::{Hash, Hasher};
10
11#[derive(Debug, Clone, PartialEq, PartialOrd)]
13pub enum MemValue {
14 Node(String),
16 Str(String),
18 Num(f64),
20 Bool(bool),
22}
23
24impl Hash for MemValue {
25 fn hash<H: Hasher>(&self, state: &mut H) {
26 std::mem::discriminant(self).hash(state);
27 match self {
28 MemValue::Node(s) => s.hash(state),
29 MemValue::Str(s) => s.hash(state),
30 MemValue::Num(n) => n.to_bits().hash(state),
31 MemValue::Bool(b) => b.hash(state),
32 }
33 }
34}
35
36impl fmt::Display for MemValue {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 match self {
39 MemValue::Node(id) => write!(f, "@{}", id),
40 MemValue::Str(s) => write!(f, "\"{}\"", s),
41 MemValue::Num(n) => write!(f, "{}", n),
42 MemValue::Bool(b) => write!(f, "{}", b),
43 }
44 }
45}
46
47#[derive(Debug, Clone)]
49struct StoredEdge {
50 source: String,
51 label: String,
52 target: MemValue,
53 interval: Interval<i64>,
54}
55
56#[derive(Clone)]
61pub struct MemGraph {
62 edges: Vec<StoredEdge>,
63 current_time: i64,
64}
65
66impl MemGraph {
67 pub fn new() -> Self {
69 Self {
70 edges: Vec::new(),
71 current_time: 0,
72 }
73 }
74
75 pub fn set_time(&mut self, t: i64) {
77 self.current_time = t;
78 }
79
80 pub fn add_edge(&mut self, source: &str, label: &str, target: MemValue, start: i64) {
82 self.edges.push(StoredEdge {
83 source: source.to_string(),
84 label: label.to_string(),
85 target,
86 interval: Interval::open(start),
87 });
88 }
89
90 pub fn add_edge_bounded(
92 &mut self,
93 source: &str,
94 label: &str,
95 target: MemValue,
96 start: i64,
97 end: i64,
98 ) {
99 self.edges.push(StoredEdge {
100 source: source.to_string(),
101 label: label.to_string(),
102 target,
103 interval: Interval::new(start, end),
104 });
105 }
106
107 pub fn add_ref(&mut self, source: &str, label: &str, target_node: &str, start: i64) {
109 self.add_edge(
110 source,
111 label,
112 MemValue::Node(target_node.to_string()),
113 start,
114 );
115 }
116
117 pub fn add_str(&mut self, source: &str, label: &str, value: &str, start: i64) {
119 self.add_edge(source, label, MemValue::Str(value.to_string()), start);
120 }
121
122 pub fn add_num(&mut self, source: &str, label: &str, value: f64, start: i64) {
124 self.add_edge(source, label, MemValue::Num(value), start);
125 }
126
127 pub fn end_edge(&mut self, source: &str, label: &str, at: i64) -> bool {
133 for edge in self.edges.iter_mut().rev() {
135 if edge.source == source && edge.label == label && edge.interval.end.is_none() {
136 edge.interval.end = Some(at);
137 return true;
138 }
139 }
140 false
141 }
142
143 pub fn upsert_edge(&mut self, source: &str, label: &str, value: MemValue, at: i64) {
149 self.end_edge(source, label, at);
150 self.add_edge(source, label, value, at);
151 }
152
153 pub fn edge_count(&self) -> usize {
155 self.edges.len()
156 }
157}
158
159impl Default for MemGraph {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165impl DataSource for MemGraph {
166 type N = String;
167 type L = String;
168 type V = MemValue;
169 type T = i64;
170
171 fn edges_from(
172 &self,
173 node: &String,
174 label: &String,
175 at: &i64,
176 ) -> Vec<Edge<String, MemValue, i64>> {
177 self.edges
178 .iter()
179 .filter(|e| &e.source == node && &e.label == label && e.interval.covers(at))
180 .map(|e| Edge {
181 source: e.source.clone(),
182 target: e.target.clone(),
183 interval: e.interval.clone(),
184 })
185 .collect()
186 }
187
188 fn scan(
189 &self,
190 label: &String,
191 constraint: &ValueConstraint<MemValue>,
192 at: &i64,
193 ) -> Vec<Edge<String, MemValue, i64>> {
194 self.edges
195 .iter()
196 .filter(|e| &e.label == label && constraint.matches(&e.target) && e.interval.covers(at))
197 .map(|e| Edge {
198 source: e.source.clone(),
199 target: e.target.clone(),
200 interval: e.interval.clone(),
201 })
202 .collect()
203 }
204
205 fn edges_from_any_time(
206 &self,
207 node: &String,
208 label: &String,
209 ) -> Vec<Edge<String, MemValue, i64>> {
210 self.edges
211 .iter()
212 .filter(|e| &e.source == node && &e.label == label)
213 .map(|e| Edge {
214 source: e.source.clone(),
215 target: e.target.clone(),
216 interval: e.interval.clone(),
217 })
218 .collect()
219 }
220
221 fn scan_any_time(
222 &self,
223 label: &String,
224 constraint: &ValueConstraint<MemValue>,
225 ) -> Vec<Edge<String, MemValue, i64>> {
226 self.edges
227 .iter()
228 .filter(|e| &e.label == label && constraint.matches(&e.target))
229 .map(|e| Edge {
230 source: e.source.clone(),
231 target: e.target.clone(),
232 interval: e.interval.clone(),
233 })
234 .collect()
235 }
236
237 fn now(&self) -> i64 {
238 self.current_time
239 }
240
241 fn value_as_node(&self, value: &MemValue) -> Option<String> {
242 match value {
243 MemValue::Node(id) => Some(id.clone()),
244 _ => None,
245 }
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 #[test]
254 fn end_edge_closes_open_interval() {
255 let mut g = MemGraph::new();
256 g.add_str("alice", "mood", "happy", 1);
257 g.set_time(5);
258
259 assert_eq!(g.edges_from(&"alice".into(), &"mood".into(), &5).len(), 1);
261
262 assert!(g.end_edge("alice", "mood", 3));
264
265 assert_eq!(g.edges_from(&"alice".into(), &"mood".into(), &2).len(), 1);
267 assert_eq!(g.edges_from(&"alice".into(), &"mood".into(), &3).len(), 0);
268 }
269
270 #[test]
271 fn end_edge_returns_false_when_no_open_edge() {
272 let mut g = MemGraph::new();
273 g.add_edge_bounded("alice", "mood", MemValue::Str("happy".into()), 1, 3);
274
275 assert!(!g.end_edge("alice", "mood", 5));
277 }
278
279 #[test]
280 fn end_edge_closes_most_recent() {
281 let mut g = MemGraph::new();
282 g.add_str("alice", "mood", "happy", 1);
283 g.add_str("alice", "mood", "sad", 5);
284
285 assert!(g.end_edge("alice", "mood", 8));
287
288 let edges = g.edges_from(&"alice".into(), &"mood".into(), &10);
290 assert_eq!(edges.len(), 1);
291 assert_eq!(edges[0].target, MemValue::Str("happy".into()));
292 }
293
294 #[test]
295 fn upsert_edge_closes_and_inserts() {
296 let mut g = MemGraph::new();
297 g.add_str("alice", "mood", "happy", 1);
298 g.set_time(5);
299
300 g.upsert_edge("alice", "mood", MemValue::Str("sad".into()), 5);
302
303 let at3 = g.edges_from(&"alice".into(), &"mood".into(), &3);
305 assert_eq!(at3.len(), 1);
306 assert_eq!(at3[0].target, MemValue::Str("happy".into()));
307
308 let at5 = g.edges_from(&"alice".into(), &"mood".into(), &5);
310 assert_eq!(at5.len(), 1);
311 assert_eq!(at5[0].target, MemValue::Str("sad".into()));
312
313 assert_eq!(g.edge_count(), 2);
315 }
316}