1use std::any::Any;
10use std::collections::HashMap;
11
12use smallvec::SmallVec;
13
14use crate::value::{EdgeId, Value, VertexId};
15
16pub trait CloneSack: Send {
31 fn clone_box(&self) -> Box<dyn CloneSack>;
33
34 fn as_any(&self) -> &dyn Any;
36}
37
38#[derive(Clone)]
43struct SackValue<T>(T);
44
45impl<T: Clone + Any + Send + 'static> CloneSack for SackValue<T> {
46 fn clone_box(&self) -> Box<dyn CloneSack> {
47 Box::new(SackValue(self.0.clone()))
48 }
49
50 fn as_any(&self) -> &dyn Any {
51 &self.0
52 }
53}
54
55pub(crate) fn box_sack<T: Clone + Any + Send + 'static>(value: T) -> Box<dyn CloneSack> {
57 Box::new(SackValue(value))
58}
59
60impl Clone for Box<dyn CloneSack> {
61 fn clone(&self) -> Self {
62 self.clone_box()
63 }
64}
65
66#[derive(Clone, Debug, PartialEq, Eq)]
75pub enum PathValue {
76 Vertex(VertexId),
78 Edge(EdgeId),
80 Property(Value),
82}
83
84impl std::hash::Hash for PathValue {
85 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
86 match self {
87 PathValue::Vertex(id) => {
88 0u8.hash(state);
89 id.hash(state);
90 }
91 PathValue::Edge(id) => {
92 1u8.hash(state);
93 id.hash(state);
94 }
95 PathValue::Property(v) => {
96 2u8.hash(state);
97 v.hash(state);
98 }
99 }
100 }
101}
102
103impl From<&Value> for PathValue {
104 fn from(value: &Value) -> Self {
105 match value {
106 Value::Vertex(id) => PathValue::Vertex(*id),
107 Value::Edge(id) => PathValue::Edge(*id),
108 other => PathValue::Property(other.clone()),
109 }
110 }
111}
112
113impl From<Value> for PathValue {
114 fn from(value: Value) -> Self {
115 match value {
116 Value::Vertex(id) => PathValue::Vertex(id),
117 Value::Edge(id) => PathValue::Edge(id),
118 other => PathValue::Property(other),
119 }
120 }
121}
122
123impl From<VertexId> for PathValue {
124 fn from(id: VertexId) -> Self {
125 PathValue::Vertex(id)
126 }
127}
128
129impl From<EdgeId> for PathValue {
130 fn from(id: EdgeId) -> Self {
131 PathValue::Edge(id)
132 }
133}
134
135impl PathValue {
136 #[inline]
138 pub fn is_vertex(&self) -> bool {
139 matches!(self, PathValue::Vertex(_))
140 }
141
142 #[inline]
144 pub fn is_edge(&self) -> bool {
145 matches!(self, PathValue::Edge(_))
146 }
147
148 #[inline]
150 pub fn as_vertex_id(&self) -> Option<VertexId> {
151 match self {
152 PathValue::Vertex(id) => Some(*id),
153 _ => None,
154 }
155 }
156
157 #[inline]
159 pub fn as_edge_id(&self) -> Option<EdgeId> {
160 match self {
161 PathValue::Edge(id) => Some(*id),
162 _ => None,
163 }
164 }
165
166 pub fn to_value(&self) -> Value {
168 match self {
169 PathValue::Vertex(id) => Value::Vertex(*id),
170 PathValue::Edge(id) => Value::Edge(*id),
171 PathValue::Property(v) => v.clone(),
172 }
173 }
174}
175
176#[derive(Clone, Debug)]
185pub struct PathElement {
186 pub value: PathValue,
188 pub labels: SmallVec<[String; 2]>,
190}
191
192impl PathElement {
193 pub fn new(value: PathValue) -> Self {
195 Self {
196 value,
197 labels: SmallVec::new(),
198 }
199 }
200
201 pub fn with_labels(value: PathValue, labels: impl IntoIterator<Item = String>) -> Self {
203 Self {
204 value,
205 labels: labels.into_iter().collect(),
206 }
207 }
208}
209
210#[derive(Clone, Default, Debug)]
232pub struct Path {
233 objects: Vec<PathElement>,
235 labels: HashMap<String, Vec<usize>>,
237}
238
239impl Path {
240 pub fn new() -> Self {
242 Self::default()
243 }
244
245 pub fn push(&mut self, value: PathValue, labels: &[String]) {
252 let idx = self.objects.len();
253
254 for label in labels {
256 self.labels.entry(label.clone()).or_default().push(idx);
257 }
258
259 self.objects.push(PathElement {
260 value,
261 labels: labels.iter().cloned().collect(),
262 });
263 }
264
265 pub fn push_labeled(&mut self, value: PathValue, label: &str) {
267 self.push(value, &[label.to_string()]);
268 }
269
270 pub fn push_unlabeled(&mut self, value: PathValue) {
272 self.push(value, &[]);
273 }
274
275 pub fn get(&self, label: &str) -> Option<Vec<&PathValue>> {
279 self.labels
280 .get(label)
281 .map(|indices| indices.iter().map(|&i| &self.objects[i].value).collect())
282 }
283
284 pub fn objects(&self) -> impl Iterator<Item = &PathValue> {
286 self.objects.iter().map(|e| &e.value)
287 }
288
289 pub fn elements(&self) -> impl Iterator<Item = &PathElement> {
291 self.objects.iter()
292 }
293
294 pub fn contains_vertex(&self, id: VertexId) -> bool {
296 self.objects
297 .iter()
298 .any(|e| matches!(&e.value, PathValue::Vertex(v) if *v == id))
299 }
300
301 pub fn contains_edge(&self, id: EdgeId) -> bool {
303 self.objects
304 .iter()
305 .any(|e| matches!(&e.value, PathValue::Edge(e) if *e == id))
306 }
307
308 pub fn has_label(&self, label: &str) -> bool {
310 self.labels.contains_key(label)
311 }
312
313 pub fn all_labels(&self) -> impl Iterator<Item = &String> {
315 self.labels.keys()
316 }
317
318 #[inline]
320 pub fn len(&self) -> usize {
321 self.objects.len()
322 }
323
324 #[inline]
326 pub fn is_empty(&self) -> bool {
327 self.objects.is_empty()
328 }
329
330 pub fn last(&self) -> Option<&PathValue> {
332 self.objects.last().map(|e| &e.value)
333 }
334
335 pub fn label_or_push(&mut self, label: &str, current_value: PathValue) {
346 if let Some(last_idx) = self.objects.len().checked_sub(1) {
348 if self.objects[last_idx].value == current_value {
349 self.objects[last_idx].labels.push(label.to_string());
351 self.labels
352 .entry(label.to_string())
353 .or_default()
354 .push(last_idx);
355 return;
356 }
357 }
358 self.push_labeled(current_value, label);
360 }
361
362 pub fn first(&self) -> Option<&PathValue> {
364 self.objects.first().map(|e| &e.value)
365 }
366
367 pub fn to_list(&self) -> Vec<Value> {
369 self.objects.iter().map(|e| e.value.to_value()).collect()
370 }
371}
372
373#[derive(Clone)]
401pub struct Traverser {
402 pub value: Value,
404 pub path: Path,
406 pub loops: usize,
408 pub sack: Option<Box<dyn CloneSack>>,
410 pub bulk: u64,
412}
413
414impl Traverser {
415 pub fn new(value: impl Into<Value>) -> Self {
421 Self {
422 value: value.into(),
423 path: Path::default(),
424 loops: 0,
425 sack: None,
426 bulk: 1,
427 }
428 }
429
430 pub fn from_vertex(id: VertexId) -> Self {
436 Self::new(Value::Vertex(id))
437 }
438
439 pub fn from_edge(id: EdgeId) -> Self {
445 Self::new(Value::Edge(id))
446 }
447
448 pub fn split(&self, new_value: impl Into<Value>) -> Traverser {
458 Traverser {
459 value: new_value.into(),
460 path: self.path.clone(),
461 loops: self.loops,
462 sack: self.sack.clone(),
463 bulk: self.bulk,
464 }
465 }
466
467 pub fn with_value(self, new_value: impl Into<Value>) -> Traverser {
476 Traverser {
477 value: new_value.into(),
478 path: self.path,
479 loops: self.loops,
480 sack: self.sack,
481 bulk: self.bulk,
482 }
483 }
484
485 pub fn inc_loops(&mut self) {
489 self.loops += 1;
490 }
491
492 #[inline]
496 pub fn loops(&self) -> usize {
497 self.loops
498 }
499
500 pub fn extend_path(&mut self, labels: &[String]) {
508 let path_value = PathValue::from(&self.value);
509 self.path.push(path_value, labels);
510 }
511
512 pub fn extend_path_labeled(&mut self, label: &str) {
514 self.extend_path(&[label.to_string()]);
515 }
516
517 pub fn extend_path_unlabeled(&mut self) {
519 self.extend_path(&[]);
520 }
521
522 pub fn label_path_position(&mut self, label: &str) {
528 let current = PathValue::from(&self.value);
529 self.path.label_or_push(label, current);
530 }
531
532 #[inline]
534 pub fn as_vertex_id(&self) -> Option<VertexId> {
535 self.value.as_vertex_id()
536 }
537
538 #[inline]
540 pub fn as_edge_id(&self) -> Option<EdgeId> {
541 self.value.as_edge_id()
542 }
543
544 #[inline]
546 pub fn is_vertex(&self) -> bool {
547 self.value.is_vertex()
548 }
549
550 #[inline]
552 pub fn is_edge(&self) -> bool {
553 self.value.is_edge()
554 }
555
556 pub fn get_sack<T: Clone + Any + Send + 'static>(&self) -> Option<&T> {
558 self.sack.as_ref().and_then(|s| s.as_any().downcast_ref())
559 }
560
561 pub fn set_sack<T: Clone + Any + Send + 'static>(&mut self, value: T) {
563 self.sack = Some(box_sack(value));
564 }
565
566 pub fn clear_sack(&mut self) {
568 self.sack = None;
569 }
570
571 #[inline]
573 pub fn bulk(&self) -> u64 {
574 self.bulk
575 }
576
577 #[inline]
579 pub fn set_bulk(&mut self, bulk: u64) {
580 self.bulk = bulk;
581 }
582}
583
584impl std::fmt::Debug for Traverser {
585 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
586 f.debug_struct("Traverser")
587 .field("value", &self.value)
588 .field("path", &self.path)
589 .field("loops", &self.loops)
590 .field("sack", &self.sack.is_some())
591 .field("bulk", &self.bulk)
592 .finish()
593 }
594}
595
596#[derive(Clone, Debug)]
605pub enum TraversalSource {
606 AllVertices,
608 Vertices(Vec<VertexId>),
610 AllEdges,
612 Edges(Vec<EdgeId>),
614 Inject(Vec<Value>),
616 #[cfg(feature = "full-text")]
625 VerticesWithTextScore(Vec<(VertexId, f32)>),
626 #[cfg(feature = "full-text")]
632 EdgesWithTextScore(Vec<(EdgeId, f32)>),
633}
634
635#[cfg(test)]
640mod tests {
641 use super::*;
642
643 mod path_value_tests {
644 use super::*;
645
646 #[test]
647 fn from_value_vertex() {
648 let v = Value::Vertex(VertexId(42));
649 let pv = PathValue::from(&v);
650 assert_eq!(pv, PathValue::Vertex(VertexId(42)));
651 }
652
653 #[test]
654 fn from_value_edge() {
655 let v = Value::Edge(EdgeId(99));
656 let pv = PathValue::from(&v);
657 assert_eq!(pv, PathValue::Edge(EdgeId(99)));
658 }
659
660 #[test]
661 fn from_value_property() {
662 let v = Value::Int(42);
663 let pv = PathValue::from(&v);
664 assert_eq!(pv, PathValue::Property(Value::Int(42)));
665
666 let v2 = Value::String("hello".to_string());
667 let pv2 = PathValue::from(&v2);
668 assert_eq!(pv2, PathValue::Property(Value::String("hello".to_string())));
669 }
670
671 #[test]
672 fn is_vertex() {
673 assert!(PathValue::Vertex(VertexId(1)).is_vertex());
674 assert!(!PathValue::Edge(EdgeId(1)).is_vertex());
675 assert!(!PathValue::Property(Value::Int(1)).is_vertex());
676 }
677
678 #[test]
679 fn is_edge() {
680 assert!(PathValue::Edge(EdgeId(1)).is_edge());
681 assert!(!PathValue::Vertex(VertexId(1)).is_edge());
682 assert!(!PathValue::Property(Value::Int(1)).is_edge());
683 }
684
685 #[test]
686 fn as_vertex_id() {
687 assert_eq!(
688 PathValue::Vertex(VertexId(42)).as_vertex_id(),
689 Some(VertexId(42))
690 );
691 assert_eq!(PathValue::Edge(EdgeId(42)).as_vertex_id(), None);
692 assert_eq!(PathValue::Property(Value::Int(42)).as_vertex_id(), None);
693 }
694
695 #[test]
696 fn as_edge_id() {
697 assert_eq!(PathValue::Edge(EdgeId(99)).as_edge_id(), Some(EdgeId(99)));
698 assert_eq!(PathValue::Vertex(VertexId(99)).as_edge_id(), None);
699 assert_eq!(PathValue::Property(Value::Int(99)).as_edge_id(), None);
700 }
701
702 #[test]
703 fn to_value() {
704 assert_eq!(
705 PathValue::Vertex(VertexId(1)).to_value(),
706 Value::Vertex(VertexId(1))
707 );
708 assert_eq!(
709 PathValue::Edge(EdgeId(2)).to_value(),
710 Value::Edge(EdgeId(2))
711 );
712 assert_eq!(
713 PathValue::Property(Value::String("test".to_string())).to_value(),
714 Value::String("test".to_string())
715 );
716 }
717 }
718
719 mod path_tests {
720 use super::*;
721
722 #[test]
723 fn new_path_is_empty() {
724 let path = Path::new();
725 assert!(path.is_empty());
726 assert_eq!(path.len(), 0);
727 }
728
729 #[test]
730 fn push_adds_elements() {
731 let mut path = Path::new();
732 path.push(PathValue::Vertex(VertexId(1)), &[]);
733 assert_eq!(path.len(), 1);
734 assert!(!path.is_empty());
735
736 path.push(PathValue::Edge(EdgeId(1)), &[]);
737 assert_eq!(path.len(), 2);
738
739 path.push(PathValue::Vertex(VertexId(2)), &[]);
740 assert_eq!(path.len(), 3);
741 }
742
743 #[test]
744 fn push_with_labels() {
745 let mut path = Path::new();
746 path.push(
747 PathValue::Vertex(VertexId(1)),
748 &["start".to_string(), "source".to_string()],
749 );
750 path.push(PathValue::Vertex(VertexId(2)), &["end".to_string()]);
751
752 assert!(path.has_label("start"));
753 assert!(path.has_label("source"));
754 assert!(path.has_label("end"));
755 assert!(!path.has_label("middle"));
756 }
757
758 #[test]
759 fn get_by_label() {
760 let mut path = Path::new();
761 path.push(PathValue::Vertex(VertexId(1)), &["a".to_string()]);
762 path.push(PathValue::Vertex(VertexId(2)), &["b".to_string()]);
763 path.push(PathValue::Vertex(VertexId(3)), &["a".to_string()]); let a_values = path.get("a").unwrap();
766 assert_eq!(a_values.len(), 2);
767 assert_eq!(a_values[0].as_vertex_id(), Some(VertexId(1)));
768 assert_eq!(a_values[1].as_vertex_id(), Some(VertexId(3)));
769
770 let b_values = path.get("b").unwrap();
771 assert_eq!(b_values.len(), 1);
772 assert_eq!(b_values[0].as_vertex_id(), Some(VertexId(2)));
773
774 assert!(path.get("nonexistent").is_none());
775 }
776
777 #[test]
778 fn objects_iterator() {
779 let mut path = Path::new();
780 path.push(PathValue::Vertex(VertexId(1)), &[]);
781 path.push(PathValue::Edge(EdgeId(2)), &[]);
782 path.push(PathValue::Vertex(VertexId(3)), &[]);
783
784 let objects: Vec<_> = path.objects().collect();
785 assert_eq!(objects.len(), 3);
786 assert_eq!(objects[0], &PathValue::Vertex(VertexId(1)));
787 assert_eq!(objects[1], &PathValue::Edge(EdgeId(2)));
788 assert_eq!(objects[2], &PathValue::Vertex(VertexId(3)));
789 }
790
791 #[test]
792 fn contains_vertex() {
793 let mut path = Path::new();
794 path.push(PathValue::Vertex(VertexId(1)), &[]);
795 path.push(PathValue::Edge(EdgeId(2)), &[]);
796 path.push(PathValue::Vertex(VertexId(3)), &[]);
797
798 assert!(path.contains_vertex(VertexId(1)));
799 assert!(path.contains_vertex(VertexId(3)));
800 assert!(!path.contains_vertex(VertexId(2)));
801 assert!(!path.contains_vertex(VertexId(99)));
802 }
803
804 #[test]
805 fn contains_edge() {
806 let mut path = Path::new();
807 path.push(PathValue::Vertex(VertexId(1)), &[]);
808 path.push(PathValue::Edge(EdgeId(2)), &[]);
809 path.push(PathValue::Vertex(VertexId(3)), &[]);
810
811 assert!(path.contains_edge(EdgeId(2)));
812 assert!(!path.contains_edge(EdgeId(1)));
813 assert!(!path.contains_edge(EdgeId(99)));
814 }
815
816 #[test]
817 fn first_and_last() {
818 let mut path = Path::new();
819 assert!(path.first().is_none());
820 assert!(path.last().is_none());
821
822 path.push(PathValue::Vertex(VertexId(1)), &[]);
823 assert_eq!(path.first(), Some(&PathValue::Vertex(VertexId(1))));
824 assert_eq!(path.last(), Some(&PathValue::Vertex(VertexId(1))));
825
826 path.push(PathValue::Vertex(VertexId(2)), &[]);
827 path.push(PathValue::Vertex(VertexId(3)), &[]);
828 assert_eq!(path.first(), Some(&PathValue::Vertex(VertexId(1))));
829 assert_eq!(path.last(), Some(&PathValue::Vertex(VertexId(3))));
830 }
831
832 #[test]
833 fn to_list() {
834 let mut path = Path::new();
835 path.push(PathValue::Vertex(VertexId(1)), &[]);
836 path.push(PathValue::Edge(EdgeId(2)), &[]);
837 path.push(PathValue::Property(Value::Int(42)), &[]);
838
839 let list = path.to_list();
840 assert_eq!(list.len(), 3);
841 assert_eq!(list[0], Value::Vertex(VertexId(1)));
842 assert_eq!(list[1], Value::Edge(EdgeId(2)));
843 assert_eq!(list[2], Value::Int(42));
844 }
845
846 #[test]
847 fn clone_preserves_data() {
848 let mut path = Path::new();
849 path.push(PathValue::Vertex(VertexId(1)), &["start".to_string()]);
850 path.push(PathValue::Vertex(VertexId(2)), &["end".to_string()]);
851
852 let cloned = path.clone();
853 assert_eq!(cloned.len(), 2);
854 assert!(cloned.has_label("start"));
855 assert!(cloned.has_label("end"));
856 assert!(cloned.contains_vertex(VertexId(1)));
857 assert!(cloned.contains_vertex(VertexId(2)));
858 }
859 }
860
861 mod traverser_tests {
862 use super::*;
863
864 #[test]
865 fn new_creates_traverser_with_value() {
866 let t = Traverser::new(Value::Int(42));
867 assert_eq!(t.value, Value::Int(42));
868 assert!(t.path.is_empty());
869 assert_eq!(t.loops, 0);
870 assert!(t.sack.is_none());
871 assert_eq!(t.bulk, 1);
872 }
873
874 #[test]
875 fn new_with_into_value() {
876 let t1 = Traverser::new(42i64);
878 assert_eq!(t1.value, Value::Int(42));
879
880 let t2 = Traverser::new("hello");
881 assert_eq!(t2.value, Value::String("hello".to_string()));
882
883 let t3 = Traverser::new(true);
884 assert_eq!(t3.value, Value::Bool(true));
885 }
886
887 #[test]
888 fn from_vertex_creates_vertex_traverser() {
889 let t = Traverser::from_vertex(VertexId(123));
890 assert_eq!(t.value, Value::Vertex(VertexId(123)));
891 assert_eq!(t.as_vertex_id(), Some(VertexId(123)));
892 assert!(t.is_vertex());
893 assert!(!t.is_edge());
894 }
895
896 #[test]
897 fn from_edge_creates_edge_traverser() {
898 let t = Traverser::from_edge(EdgeId(456));
899 assert_eq!(t.value, Value::Edge(EdgeId(456)));
900 assert_eq!(t.as_edge_id(), Some(EdgeId(456)));
901 assert!(t.is_edge());
902 assert!(!t.is_vertex());
903 }
904
905 #[test]
906 fn split_preserves_path_and_metadata() {
907 let mut t = Traverser::from_vertex(VertexId(1));
908 t.extend_path_labeled("start");
909 t.loops = 5;
910 t.bulk = 10;
911
912 let t2 = t.split(Value::Vertex(VertexId(2)));
913
914 assert_eq!(t2.value, Value::Vertex(VertexId(2)));
916
917 assert_eq!(t2.path.len(), t.path.len());
919 assert!(t2.path.has_label("start"));
920 assert_eq!(t2.loops, 5);
921 assert_eq!(t2.bulk, 10);
922 }
923
924 #[test]
925 fn with_value_replaces_value() {
926 let t = Traverser::from_vertex(VertexId(1));
927 let t2 = t.with_value(Value::Int(42));
928
929 assert_eq!(t2.value, Value::Int(42));
930 }
931
932 #[test]
933 fn inc_loops_increments() {
934 let mut t = Traverser::new(Value::Null);
935 assert_eq!(t.loops, 0);
936
937 t.inc_loops();
938 assert_eq!(t.loops, 1);
939
940 t.inc_loops();
941 assert_eq!(t.loops, 2);
942 }
943
944 #[test]
945 fn loops_returns_loop_count() {
946 let mut t = Traverser::new(Value::Null);
947 assert_eq!(t.loops(), 0);
948
949 t.inc_loops();
950 assert_eq!(t.loops(), 1);
951
952 t.inc_loops();
953 t.inc_loops();
954 assert_eq!(t.loops(), 3);
955 }
956
957 #[test]
958 fn split_preserves_loop_count() {
959 let mut t = Traverser::from_vertex(VertexId(1));
960 t.inc_loops();
961 t.inc_loops();
962 t.inc_loops();
963 assert_eq!(t.loops(), 3);
964
965 let t2 = t.split(Value::Vertex(VertexId(2)));
966 assert_eq!(t2.loops(), 3);
967 }
968
969 #[test]
970 fn extend_path_adds_to_path() {
971 let mut t = Traverser::from_vertex(VertexId(1));
972 assert!(t.path.is_empty());
973
974 t.extend_path_labeled("a");
975 assert_eq!(t.path.len(), 1);
976 assert!(t.path.has_label("a"));
977
978 t.value = Value::Vertex(VertexId(2));
979 t.extend_path(&["b".to_string(), "c".to_string()]);
980 assert_eq!(t.path.len(), 2);
981 assert!(t.path.has_label("b"));
982 assert!(t.path.has_label("c"));
983 }
984
985 #[test]
986 fn as_vertex_id_returns_vertex_id() {
987 let t = Traverser::from_vertex(VertexId(42));
988 assert_eq!(t.as_vertex_id(), Some(VertexId(42)));
989
990 let t2 = Traverser::from_edge(EdgeId(42));
991 assert_eq!(t2.as_vertex_id(), None);
992
993 let t3 = Traverser::new(Value::Int(42));
994 assert_eq!(t3.as_vertex_id(), None);
995 }
996
997 #[test]
998 fn as_edge_id_returns_edge_id() {
999 let t = Traverser::from_edge(EdgeId(99));
1000 assert_eq!(t.as_edge_id(), Some(EdgeId(99)));
1001
1002 let t2 = Traverser::from_vertex(VertexId(99));
1003 assert_eq!(t2.as_edge_id(), None);
1004
1005 let t3 = Traverser::new(Value::Int(99));
1006 assert_eq!(t3.as_edge_id(), None);
1007 }
1008
1009 #[test]
1010 fn clone_works_correctly() {
1011 let mut t = Traverser::from_vertex(VertexId(1));
1012 t.extend_path_labeled("start");
1013 t.loops = 3;
1014 t.bulk = 5;
1015
1016 let cloned = t.clone();
1017
1018 assert_eq!(cloned.value, t.value);
1019 assert_eq!(cloned.path.len(), t.path.len());
1020 assert_eq!(cloned.loops, t.loops);
1021 assert_eq!(cloned.bulk, t.bulk);
1022 }
1023
1024 #[test]
1025 fn sack_operations() {
1026 let mut t = Traverser::new(Value::Null);
1027
1028 assert!(t.get_sack::<i32>().is_none());
1030
1031 t.set_sack(42i32);
1033 assert_eq!(t.get_sack::<i32>(), Some(&42));
1034
1035 assert!(t.get_sack::<String>().is_none());
1037
1038 t.clear_sack();
1040 assert!(t.get_sack::<i32>().is_none());
1041 }
1042
1043 #[test]
1044 fn bulk_operations() {
1045 let mut t = Traverser::new(Value::Null);
1046 assert_eq!(t.bulk(), 1);
1047
1048 t.set_bulk(100);
1049 assert_eq!(t.bulk(), 100);
1050 }
1051
1052 #[test]
1053 fn debug_output() {
1054 let t = Traverser::from_vertex(VertexId(1));
1055 let debug_str = format!("{:?}", t);
1056 assert!(debug_str.contains("Traverser"));
1057 assert!(debug_str.contains("value"));
1058 assert!(debug_str.contains("path"));
1059 }
1060 }
1061
1062 mod clone_sack_tests {
1063 use super::*;
1064
1065 #[test]
1066 fn clone_box_works() {
1067 let boxed: Box<dyn CloneSack> = box_sack(42i32);
1068 let cloned = boxed.clone_box();
1069 assert_eq!(cloned.as_any().downcast_ref::<i32>(), Some(&42));
1070 }
1071
1072 #[test]
1073 fn clone_trait_impl_works() {
1074 let boxed: Box<dyn CloneSack> = box_sack("hello".to_string());
1075 let cloned = boxed.clone();
1076 assert_eq!(
1077 cloned.as_any().downcast_ref::<String>(),
1078 Some(&"hello".to_string())
1079 );
1080 }
1081
1082 #[test]
1083 fn sack_preserves_on_split() {
1084 let mut t = Traverser::new(Value::Int(1));
1085 t.set_sack(vec![1, 2, 3]);
1086
1087 let t2 = t.split(Value::Int(2));
1088
1089 assert_eq!(t2.get_sack::<Vec<i32>>(), Some(&vec![1, 2, 3]));
1091 }
1092 }
1093
1094 mod traversal_source_tests {
1095 use super::*;
1096
1097 #[test]
1098 fn all_vertices_source() {
1099 let source = TraversalSource::AllVertices;
1100 assert!(matches!(source, TraversalSource::AllVertices));
1101 }
1102
1103 #[test]
1104 fn specific_vertices_source() {
1105 let source = TraversalSource::Vertices(vec![VertexId(1), VertexId(2)]);
1106 match source {
1107 TraversalSource::Vertices(ids) => {
1108 assert_eq!(ids.len(), 2);
1109 assert_eq!(ids[0], VertexId(1));
1110 assert_eq!(ids[1], VertexId(2));
1111 }
1112 _ => panic!("Expected Vertices variant"),
1113 }
1114 }
1115
1116 #[test]
1117 fn all_edges_source() {
1118 let source = TraversalSource::AllEdges;
1119 assert!(matches!(source, TraversalSource::AllEdges));
1120 }
1121
1122 #[test]
1123 fn specific_edges_source() {
1124 let source = TraversalSource::Edges(vec![EdgeId(10), EdgeId(20)]);
1125 match source {
1126 TraversalSource::Edges(ids) => {
1127 assert_eq!(ids.len(), 2);
1128 assert_eq!(ids[0], EdgeId(10));
1129 assert_eq!(ids[1], EdgeId(20));
1130 }
1131 _ => panic!("Expected Edges variant"),
1132 }
1133 }
1134
1135 #[test]
1136 fn inject_source() {
1137 let source =
1138 TraversalSource::Inject(vec![Value::Int(1), Value::String("test".to_string())]);
1139 match source {
1140 TraversalSource::Inject(values) => {
1141 assert_eq!(values.len(), 2);
1142 assert_eq!(values[0], Value::Int(1));
1143 assert_eq!(values[1], Value::String("test".to_string()));
1144 }
1145 _ => panic!("Expected Inject variant"),
1146 }
1147 }
1148
1149 #[test]
1150 fn source_is_clonable() {
1151 let source1 = TraversalSource::AllVertices;
1152 let source2 = TraversalSource::Vertices(vec![VertexId(1)]);
1153 let source3 = TraversalSource::Inject(vec![Value::Int(42)]);
1154
1155 let _ = source1.clone();
1156 let _ = source2.clone();
1157 let _ = source3.clone();
1158 }
1159 }
1160}