1#![doc = include_str!("../README.md")]
2mod graphs;
3mod node;
4mod registry;
5mod stage;
6mod types;
7mod error;
8
9pub use directed_stage_macro::stage;
10pub use graphs::{EdgeInfo, Graph};
11pub use node::{AnyNode, Node};
12pub use registry::Registry;
13pub use stage::{EvalStrategy, ReevaluationRule, RefType, Stage};
14pub use types::{DataLabel, NodeOutput};
15pub use error::*;
16
17#[cfg(test)]
18mod tests {
19 extern crate self as directed;
20 use super::*;
21 use directed_stage_macro::stage;
22 use std::sync::atomic::{AtomicUsize, Ordering};
23
24 #[test]
26 fn basic_macro_test() {
27 #[stage(lazy, cache_last)]
28 fn TinyStage1() -> String {
29 println!("Running stage 1");
30 String::from("This is the output!")
31 }
32
33 #[stage(lazy, cache_last)]
34 fn TinyStage2(input: String, input2: String) -> String {
35 println!("Running stage 2");
36 input.to_uppercase() + " [" + &input.chars().count().to_string() + " chars]"
37 }
38
39 #[stage(cache_last)]
40 fn TinyStage3(input: String) {
41 println!("Running stage 3");
42 assert_eq!("THIS IS THE OUTPUT! [19 chars]", input);
43 }
44
45 let mut registry = Registry::new();
46 let node_1 = registry.register(TinyStage1::new());
47 let node_2 = registry.register(TinyStage2::new());
48 let node_3 = registry.register(TinyStage3::new());
49 let graph = graph! {
50 nodes: [node_1, node_2, node_3],
51 connections: {
52 node_1: _ => node_2: input,
53 node_1: _ => node_2: input2,
54 node_2: _ => node_3: input,
55 }
56 }
57 .unwrap();
58
59 graph.execute(&mut registry).unwrap();
60 }
61
62 #[test]
64 fn multiple_output_stage_test() {
65 #[stage(out(number: i32, text: String))]
66 fn MultiOutputStage() -> NodeOutput {
67 let value1 = 42;
68 let value2 = String::from("Hello");
69 output! {
70 number: value1,
71 text: value2
72 }
73 }
74
75 #[stage]
76 fn ConsumerStage1(number: i32) {
77 assert_eq!(number, 42);
78 }
79
80 #[stage]
81 fn ConsumerStage2(text: String) {
82 assert_eq!(text, "Hello");
83 }
84
85 let mut registry = Registry::new();
86 let producer = registry.register(MultiOutputStage::new());
87 let consumer1 = registry.register(ConsumerStage1::new());
88 let consumer2 = registry.register(ConsumerStage2::new());
89
90 let graph = graph! {
91 nodes: [producer, consumer1, consumer2],
92 connections: {
93 producer: number => consumer1: number,
94 producer: text => consumer2: text,
95 }
96 }
97 .unwrap();
98
99 graph.execute(&mut registry).unwrap();
100 }
101
102 #[test]
104 fn lazy_and_urgent_eval_test() {
105 static COUNTER: AtomicUsize = AtomicUsize::new(0);
106
107 #[stage(lazy, cache_last)]
108 fn LazyStage() -> i32 {
109 COUNTER.fetch_add(1, Ordering::SeqCst);
110 42
111 }
112
113 #[stage(cache_last)]
114 fn UrgentStage(input: i32) {
115 assert_eq!(input, 42);
116 assert_eq!(COUNTER.load(Ordering::SeqCst), 1);
117 }
118
119 let mut registry = Registry::new();
120 let lazy_node = registry.register(LazyStage::new());
121 let urgent_node = registry.register(UrgentStage::new());
122
123 let graph = graph! {
124 nodes: [lazy_node, urgent_node],
125 connections: {
126 lazy_node: _ => urgent_node: input,
127 }
128 }
129 .unwrap();
130
131 COUNTER.store(0, Ordering::SeqCst);
133
134 graph.execute(&mut registry).unwrap();
136 }
137
138 #[test]
140 fn transparent_opaque_reevaluation_test() {
141 static TRANSPARENT_COUNTER: AtomicUsize = AtomicUsize::new(0);
142 static OPAQUE_COUNTER: AtomicUsize = AtomicUsize::new(0);
143
144 #[stage(lazy, cache_last)]
145 fn SourceStage() -> i32 {
146 println!("SourceStage");
147 42
148 }
149
150 #[stage(lazy, cache_last)]
151 fn TransparentStage(input: i32) -> i32 {
152 println!("TransparentStage");
153 TRANSPARENT_COUNTER.fetch_add(1, Ordering::SeqCst);
154 input * 2
155 }
156
157 #[stage(lazy)]
158 fn OpaqueStage(input: &i32) -> i32 {
159 println!("OpaqueStage");
160 OPAQUE_COUNTER.fetch_add(1, Ordering::SeqCst);
161 input * 3
162 }
163
164 #[stage]
165 fn SinkStage(t_input: &i32, o_input: &i32) {
166 println!("SinkStage");
167 assert_eq!(*t_input, 84);
168 assert_eq!(*o_input, 126);
169 }
170
171 let mut registry = Registry::new();
172 let source = registry.register(SourceStage::new());
173 let transparent = registry.register(TransparentStage::new());
174 let opaque = registry.register(OpaqueStage::new());
175 let sink = registry.register(SinkStage::new());
176
177 let graph = graph! {
178 nodes: [source, transparent, opaque, sink],
179 connections: {
180 source: _ => transparent: input,
181 source: _ => opaque: input,
182 transparent: _ => sink: t_input,
183 opaque: _ => sink: o_input,
184 }
185 }
186 .unwrap();
187
188 TRANSPARENT_COUNTER.store(0, Ordering::SeqCst);
190 OPAQUE_COUNTER.store(0, Ordering::SeqCst);
191
192 graph.execute(&mut registry).unwrap();
194 assert_eq!(TRANSPARENT_COUNTER.load(Ordering::SeqCst), 1);
195 assert_eq!(OPAQUE_COUNTER.load(Ordering::SeqCst), 1);
196
197 graph.execute(&mut registry).unwrap();
199 assert_eq!(TRANSPARENT_COUNTER.load(Ordering::SeqCst), 1); assert_eq!(OPAQUE_COUNTER.load(Ordering::SeqCst), 2); println!("{}", graph.generate_trace(®istry, vec![sink], vec![(opaque, "_".into(), sink, "o_input".into())]).create_mermaid_graph());
203 }
204
205 #[test]
207 fn cycle_detection_test() {
208 #[stage]
209 fn StageA(input: i32) -> i32 {
210 input + 1
211 }
212
213 #[stage]
214 fn StageB(input: i32) -> i32 {
215 input * 2
216 }
217
218 let mut registry = Registry::new();
219 let node_a = registry.register(StageA::new());
220 let node_b = registry.register(StageB::new());
221
222 let result = graph! {
224 nodes: [node_a, node_b],
225 connections: {
226 node_a: _ => node_b: input,
227 node_b: _ => node_a: input,
228 }
229 };
230
231 assert!(result.is_err());
233 }
234
235 #[test]
237 fn registry_operations_test() {
238 #[stage]
239 fn SimpleStage() -> i32 {
240 42
241 }
242
243 let mut registry = Registry::new();
244
245 let node_id = registry.register(SimpleStage::new());
247
248 registry.validate_node_type::<SimpleStage>(node_id).unwrap();
250
251 #[stage]
253 fn OtherStage() -> String {
254 "hello".to_string()
255 }
256 assert!(registry.validate_node_type::<OtherStage>(node_id).is_err());
257
258 assert!(registry.get(node_id).is_some());
260
261 assert!(registry.get_mut(node_id).is_some());
263
264 let node = registry
266 .unregister::<SimpleStage>(node_id)
267 .unwrap()
268 .unwrap();
269 assert!(node.stage.eval_strategy() == EvalStrategy::Urgent);
270
271 assert!(registry.get(node_id).is_none());
273 }
274
275 #[test]
277 fn nonexistent_node_test() {
278 let mut registry = Registry::new();
279
280 let invalid_id = 9999;
282
283 assert!(registry.get(invalid_id).is_none());
285 assert!(registry.get_mut(invalid_id).is_none());
286 assert!(registry.unregister_and_drop(invalid_id).is_err());
287 }
288
289 #[test]
291 fn type_mismatch_test() {
292 #[stage]
293 fn StringStage() -> String {
294 "Hello".to_string()
295 }
296
297 #[stage]
298 fn IntegerConsumer(_input: i32) {
299 panic!("Should not execute");
301 }
302
303 let mut registry = Registry::new();
304 let producer = registry.register(StringStage::new());
305 let consumer = registry.register(IntegerConsumer::new());
306
307 let graph = graph! {
309 nodes: [producer, consumer],
310 connections: {
311 producer: _ => consumer: input,
312 }
313 }
314 .unwrap();
315
316 let result = graph.execute(&mut registry);
318 assert!(result.is_err());
319 }
320
321 #[test]
323 fn missing_input_test() {
324 #[stage]
325 fn ConsumerStage(_input1: i32, _input2: String) {
326 panic!("Should not execute");
328 }
329
330 #[stage]
331 fn ProducerStage() -> i32 {
332 42
333 }
334
335 let mut registry = Registry::new();
336 let producer = registry.register(ProducerStage::new());
337 let consumer = registry.register(ConsumerStage::new());
338
339 let graph = graph! {
341 nodes: [producer, consumer],
342 connections: {
343 producer: _ => consumer: input1,
344 }
345 }
346 .unwrap();
347
348 let result = graph.execute(&mut registry);
350 assert!(result.is_err());
351 }
352
353 #[test]
355 fn data_label_test() {
356 let label1 = DataLabel::new("test");
357 let label2 = DataLabel::new("test");
358 let label3 = DataLabel::new("different");
359
360 assert_eq!(label1, label2);
361 assert_ne!(label1, label3);
362
363 let const_label = DataLabel::new_const("const");
364 assert_eq!(const_label.inner(), "const");
365
366 let from_str: DataLabel = "string".into();
367 assert_eq!(from_str.inner(), "string");
368 }
369
370 #[test]
372 fn diamond_graph_test() {
373 #[stage]
374 fn Source() -> i32 {
375 10
376 }
377
378 #[stage]
379 fn PathA(input: i32) -> i32 {
380 input * 2
381 }
382
383 #[stage]
384 fn PathB(input: i32) -> i32 {
385 input + 5
386 }
387
388 #[stage]
389 fn Sink(a: i32, b: i32) {
390 assert_eq!(a, 20); assert_eq!(b, 15); }
393
394 let mut registry = Registry::new();
395 let source = registry.register(Source::new());
396 let path_a = registry.register(PathA::new());
397 let path_b = registry.register(PathB::new());
398 let sink = registry.register(Sink::new());
399
400 let graph = graph! {
401 nodes: [source, path_a, path_b, sink],
402 connections: {
403 source: _ => path_a: input,
404 source: _ => path_b: input,
405 path_a: _ => sink: a,
406 path_b: _ => sink: b,
407 }
408 }
409 .unwrap();
410
411 graph.execute(&mut registry).unwrap();
412 }
413
414 #[test]
416 fn invalid_output_name_test() {
417 #[stage]
418 fn MultiOutputStage() -> NodeOutput {
419 output! {
420 output1: 42,
421 output2: "Hello".to_string()
422 }
423 }
424
425 #[stage]
426 fn ConsumerStage(_input: i32) {
427 panic!("Should not execute");
429 }
430
431 let mut registry = Registry::new();
432 let producer = registry.register(MultiOutputStage::new());
433 let consumer = registry.register(ConsumerStage::new());
434
435 let graph = graph! {
437 nodes: [producer, consumer],
438 connections: {
439 producer: nonexistent => consumer: input,
440 }
441 }
442 .unwrap();
443
444 let result = graph.execute(&mut registry);
446 assert!(result.is_err());
447 }
448
449 #[test]
451 fn node_with_state_test() {
452 #[stage(state((u8, u8)))]
453 fn StateStage() {
454 assert_eq!(state.1, state.0 * 5);
455 state.0 += 1;
456 state.1 += 5;
457 println!("State is {}", state.1);
458 }
459
460 let mut registry = Registry::new();
461 let node = registry.register_with_state(StateStage::new(), (1, 5));
464 let graph = graph! {
465 nodes: [node],
466 connections: {}
467 }
468 .unwrap();
469
470 graph.execute(&mut registry).unwrap();
472 graph.execute(&mut registry).unwrap();
473 graph.execute(&mut registry).unwrap();
474 graph.execute(&mut registry).unwrap();
475 }
476
477 #[test]
479 fn output_macro_test() {
480 #[stage(out(number: i32, text: String, vector: Vec<i32>))]
481 fn ProduceOutput1() -> NodeOutput {
482 println!("Running ProduceOutput1");
483 let number = 42;
484 let text = "hello".to_string();
485 let vector = vec![1, 2, 3];
486
487 output! {
488 number,
489 text,
490 vector
491 }
492 }
493
494 #[stage]
495 fn ConsumeOutputs(num: i32, txt: String, vec: Vec<i32>) {
496 assert_eq!(num, 42);
497 assert_eq!(txt, "hello");
498 assert_eq!(vec, vec![1, 2, 3]);
499 }
500
501 let mut registry = Registry::new();
502 let producer = registry.register(ProduceOutput1::new());
503 let consumer = registry.register(ConsumeOutputs::new());
504
505 let graph = graph! {
506 nodes: [producer, consumer],
507 connections: {
508 producer: number => consumer: num,
509 producer: text => consumer: txt,
510 producer: vector => consumer: vec,
511 }
512 }
513 .unwrap();
514
515 graph.execute(&mut registry).unwrap();
516 }
517
518 #[test]
520 fn registry_type_validation_test() {
521 #[stage]
522 fn StageA() -> i32 {
523 42
524 }
525
526 #[stage]
527 fn StageB() -> String {
528 "hello".to_string()
529 }
530
531 let mut registry = Registry::new();
532 let node_a = registry.register(StageA::new());
533
534 assert!(registry.validate_node_type::<StageA>(node_a).is_ok());
536
537 assert!(registry.validate_node_type::<StageB>(node_a).is_err());
539
540 assert!(registry.unregister::<StageB>(node_a).is_err());
542
543 assert!(registry.unregister::<StageA>(node_a).is_ok());
545 }
546}