cljrs_value/collections/
list.rs1use std::sync::Arc;
2
3use crate::Value;
4
5#[derive(Debug, Clone)]
10pub enum PersistentList {
11 Empty,
12 Cons {
13 head: Value,
14 tail: Arc<PersistentList>,
15 count: usize,
16 },
17}
18
19impl PersistentList {
20 pub fn empty() -> Self {
22 PersistentList::Empty
23 }
24
25 pub fn cons(head: Value, tail: Arc<PersistentList>) -> Self {
27 let count = tail.count() + 1;
28 PersistentList::Cons { head, tail, count }
29 }
30
31 pub fn count(&self) -> usize {
33 match self {
34 PersistentList::Empty => 0,
35 PersistentList::Cons { count, .. } => *count,
36 }
37 }
38
39 pub fn is_empty(&self) -> bool {
40 matches!(self, PersistentList::Empty)
41 }
42
43 pub fn first(&self) -> Option<&Value> {
45 match self {
46 PersistentList::Empty => None,
47 PersistentList::Cons { head, .. } => Some(head),
48 }
49 }
50
51 pub fn rest(&self) -> Arc<PersistentList> {
54 match self {
55 PersistentList::Empty => Arc::new(PersistentList::Empty),
56 PersistentList::Cons { tail, .. } => Arc::clone(tail),
57 }
58 }
59
60 pub fn iter(&self) -> ListIter<'_> {
62 ListIter { current: self }
63 }
64}
65
66impl cljrs_gc::Trace for PersistentList {
67 #[cfg(feature = "no-gc")]
68 fn immutable_children(&self) -> bool {
69 true
70 }
71 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
72 match self {
73 PersistentList::Empty => {}
74 PersistentList::Cons { head, tail, .. } => {
75 head.trace(visitor);
76 tail.trace(visitor);
79 }
80 }
81 }
82}
83
84impl std::iter::FromIterator<Value> for PersistentList {
85 fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
86 let items: Vec<Value> = iter.into_iter().collect();
87 let mut list = PersistentList::Empty;
88 for item in items.into_iter().rev() {
89 list = PersistentList::cons(item, Arc::new(list));
90 }
91 list
92 }
93}
94
95pub struct ListIter<'a> {
97 current: &'a PersistentList,
98}
99
100impl<'a> Iterator for ListIter<'a> {
101 type Item = &'a Value;
102
103 fn next(&mut self) -> Option<Self::Item> {
104 match self.current {
105 PersistentList::Empty => None,
106 PersistentList::Cons { head, tail, .. } => {
107 self.current = tail;
108 Some(head)
109 }
110 }
111 }
112}
113
114impl PartialEq for PersistentList {
115 fn eq(&self, other: &Self) -> bool {
116 if self.count() != other.count() {
117 return false;
118 }
119 self.iter().zip(other.iter()).all(|(a, b)| a == b)
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use crate::Value;
127
128 fn int(n: i64) -> Value {
129 Value::Long(n)
130 }
131
132 #[test]
133 fn test_empty() {
134 let l = PersistentList::empty();
135 assert!(l.is_empty());
136 assert_eq!(l.count(), 0);
137 assert!(l.first().is_none());
138 }
139
140 #[test]
141 fn test_cons_and_first() {
142 let l = PersistentList::cons(int(1), Arc::new(PersistentList::empty()));
143 assert_eq!(l.count(), 1);
144 assert_eq!(l.first(), Some(&int(1)));
145 }
146
147 #[test]
148 fn test_from_iter() {
149 let l = PersistentList::from_iter([int(1), int(2), int(3)]);
150 assert_eq!(l.count(), 3);
151 let items: Vec<_> = l.iter().cloned().collect();
152 assert_eq!(items, vec![int(1), int(2), int(3)]);
153 }
154
155 #[test]
156 fn test_rest() {
157 let l = PersistentList::from_iter([int(1), int(2)]);
158 let rest = l.rest();
159 assert_eq!(rest.count(), 1);
160 assert_eq!(rest.first(), Some(&int(2)));
161 }
162
163 #[test]
164 fn test_equality() {
165 let a = PersistentList::from_iter([int(1), int(2)]);
166 let b = PersistentList::from_iter([int(1), int(2)]);
167 let c = PersistentList::from_iter([int(1), int(3)]);
168 assert_eq!(a, b);
169 assert_ne!(a, c);
170 }
171
172 #[test]
173 fn test_structural_sharing() {
174 let tail = Arc::new(PersistentList::from_iter([int(2), int(3)]));
175 let a = PersistentList::cons(int(1), Arc::clone(&tail));
176 let b = PersistentList::cons(int(10), Arc::clone(&tail));
177 assert!(Arc::ptr_eq(&a.rest(), &b.rest()));
179 }
180}