Skip to main content

cljrs_value/collections/
vector.rs

1use crate::Value;
2
3/// An immutable persistent vector backed by `rpds::Vector`.
4///
5/// A vector may additionally be tagged as a *map entry* (see
6/// [`PersistentVector::map_entry`]): a two-element `[key val]` pair produced
7/// by seq'ing a map, `find`, or the `map-entry` builtin. Map entries behave
8/// exactly like vectors (equality, hashing, printing, indexing) — the tag
9/// only answers `map-entry?` — and, as in Clojure, any derived vector
10/// (`conj`, `assoc`, `pop`, ...) is a plain vector again.
11#[derive(Debug, Clone)]
12pub struct PersistentVector {
13    inner: rpds::VectorSync<Value>,
14    is_map_entry: bool,
15}
16
17impl PersistentVector {
18    pub fn empty() -> Self {
19        Self {
20            inner: rpds::VectorSync::new_sync(),
21            is_map_entry: false,
22        }
23    }
24
25    pub fn from_vector(vector: rpds::VectorSync<Value>) -> Self {
26        Self {
27            inner: vector,
28            is_map_entry: false,
29        }
30    }
31
32    /// Build a `[key val]` pair tagged as a map entry.
33    pub fn map_entry(key: Value, val: Value) -> Self {
34        let mut inner = rpds::VectorSync::new_sync();
35        inner = inner.push_back(key);
36        inner = inner.push_back(val);
37        Self {
38            inner,
39            is_map_entry: true,
40        }
41    }
42
43    /// True only for vectors created via [`PersistentVector::map_entry`].
44    pub fn is_map_entry(&self) -> bool {
45        self.is_map_entry
46    }
47
48    pub fn count(&self) -> usize {
49        self.inner.len()
50    }
51
52    pub fn is_empty(&self) -> bool {
53        self.inner.is_empty()
54    }
55
56    /// Append a value. O(log n) amortized.
57    pub fn conj(&self, val: Value) -> Self {
58        Self {
59            inner: self.inner.push_back(val),
60            is_map_entry: false,
61        }
62    }
63
64    /// Return the element at `idx`, or `None` if out of bounds.
65    pub fn nth(&self, idx: usize) -> Option<&Value> {
66        self.inner.get(idx)
67    }
68
69    /// Last element.
70    pub fn peek(&self) -> Option<&Value> {
71        self.inner.last()
72    }
73
74    /// Return a new vector with element `idx` replaced, or appended if `idx == len`.
75    pub fn assoc_nth(&self, idx: usize, val: Value) -> Option<Self> {
76        if idx == self.inner.len() {
77            Some(self.conj(val))
78        } else {
79            Some(Self {
80                inner: self.inner.set(idx, val)?,
81                is_map_entry: false,
82            })
83        }
84    }
85
86    /// Remove the last element. Returns `None` if empty.
87    pub fn pop(&self) -> Option<Self> {
88        Some(Self {
89            inner: self.inner.drop_last()?,
90            is_map_entry: false,
91        })
92    }
93
94    /// Iterate over elements in index order.
95    pub fn iter(&self) -> impl Iterator<Item = &Value> {
96        self.inner.iter()
97    }
98
99    pub fn inner(&self) -> &rpds::VectorSync<Value> {
100        &self.inner
101    }
102}
103
104impl std::iter::FromIterator<Value> for PersistentVector {
105    fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
106        let mut v = rpds::VectorSync::new_sync();
107        for item in iter {
108            v = v.push_back(item);
109        }
110        Self {
111            inner: v,
112            is_map_entry: false,
113        }
114    }
115}
116
117impl PartialEq for PersistentVector {
118    fn eq(&self, other: &Self) -> bool {
119        if self.inner.len() != other.inner.len() {
120            return false;
121        }
122        self.iter().zip(other.iter()).all(|(a, b)| a == b)
123    }
124}
125
126impl cljrs_gc::Trace for PersistentVector {
127    fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
128        for v in self.inner.iter() {
129            v.trace(visitor);
130        }
131    }
132
133    fn gc_size_extra(&self) -> usize {
134        // Per element: Arc<T> allocation (16 overhead) + thin ptr in leaf node (8).
135        let n = self.inner.len();
136        n * (24 + std::mem::size_of::<Value>())
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use crate::Value;
144
145    fn int(n: i64) -> Value {
146        Value::Long(n)
147    }
148
149    #[test]
150    fn test_empty() {
151        let v = PersistentVector::empty();
152        assert!(v.is_empty());
153        assert_eq!(v.count(), 0);
154        assert!(v.nth(0).is_none());
155    }
156
157    #[test]
158    fn test_conj_small() {
159        let v = PersistentVector::from_iter([int(1), int(2), int(3)]);
160        assert_eq!(v.count(), 3);
161        assert_eq!(v.nth(0), Some(&int(1)));
162        assert_eq!(v.nth(2), Some(&int(3)));
163    }
164
165    #[test]
166    fn test_conj_forces_tail_flush() {
167        let v = PersistentVector::from_iter((0..33).map(int));
168        assert_eq!(v.count(), 33);
169        for i in 0..33 {
170            assert_eq!(v.nth(i), Some(&int(i as i64)), "nth({i}) wrong");
171        }
172    }
173
174    #[test]
175    fn test_large() {
176        let n = 1025;
177        let v = PersistentVector::from_iter((0..n).map(|i| int(i as i64)));
178        assert_eq!(v.count(), n);
179        for i in 0..n {
180            assert_eq!(v.nth(i), Some(&int(i as i64)));
181        }
182    }
183
184    #[test]
185    fn test_peek() {
186        let v = PersistentVector::from_iter([int(1), int(2), int(3)]);
187        assert_eq!(v.peek(), Some(&int(3)));
188    }
189
190    #[test]
191    fn test_assoc_nth() {
192        let v = PersistentVector::from_iter([int(1), int(2), int(3)]);
193        let v2 = v.assoc_nth(1, int(99)).unwrap();
194        assert_eq!(v2.nth(0), Some(&int(1)));
195        assert_eq!(v2.nth(1), Some(&int(99)));
196        assert_eq!(v2.nth(2), Some(&int(3)));
197        // Original unchanged.
198        assert_eq!(v.nth(1), Some(&int(2)));
199    }
200
201    #[test]
202    fn test_pop() {
203        let v = PersistentVector::from_iter([int(1), int(2), int(3)]);
204        let v2 = v.pop().unwrap();
205        assert_eq!(v2.count(), 2);
206        assert_eq!(v2.nth(0), Some(&int(1)));
207        assert_eq!(v2.nth(1), Some(&int(2)));
208    }
209
210    #[test]
211    fn test_equality() {
212        let a = PersistentVector::from_iter([int(1), int(2)]);
213        let b = PersistentVector::from_iter([int(1), int(2)]);
214        let c = PersistentVector::from_iter([int(1), int(3)]);
215        assert_eq!(a, b);
216        assert_ne!(a, c);
217    }
218
219    #[test]
220    fn test_map_entry_flag() {
221        let e = PersistentVector::map_entry(int(1), int(2));
222        assert!(e.is_map_entry());
223        assert_eq!(e.count(), 2);
224        assert_eq!(e.nth(0), Some(&int(1)));
225        assert_eq!(e.nth(1), Some(&int(2)));
226        // Equal to a plain vector with the same elements.
227        assert_eq!(e, PersistentVector::from_iter([int(1), int(2)]));
228        // Plain constructors never produce map entries.
229        assert!(!PersistentVector::from_iter([int(1), int(2)]).is_map_entry());
230        // Derived vectors are plain vectors again.
231        assert!(!e.conj(int(3)).is_map_entry());
232        assert!(!e.assoc_nth(0, int(9)).unwrap().is_map_entry());
233        assert!(!e.pop().unwrap().is_map_entry());
234    }
235
236    #[test]
237    fn test_iter_order() {
238        let v = PersistentVector::from_iter((0..10).map(|i| int(i as i64)));
239        let items: Vec<_> = v.iter().cloned().collect();
240        assert_eq!(items, (0..10).map(|i| int(i as i64)).collect::<Vec<_>>());
241    }
242}