Skip to main content

hara_native/lang/data/
seq.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4use crate::lang::hash::JavaHash;
5use crate::lang::protocol::{
6    HashType, ICons, ICount, IDisplay, IEmpty, IEquality, IHash, IMetadata, IObjType, IPeekFirst,
7    IPersistent, IPopFirst, IPushFirst, ObjType,
8};
9
10#[derive(Clone)]
11pub struct Seq<E> {
12    metadata: Option<Rc<crate::lang::data::Metadata>>,
13    state: Rc<RefCell<State<E>>>,
14    offset: usize,
15}
16struct State<E> {
17    source: Option<Box<dyn Iterator<Item = E>>>,
18    realized: Vec<E>,
19}
20
21impl<E: Clone + 'static> Seq<E> {
22    pub fn new(source: impl Iterator<Item = E> + 'static) -> Self {
23        Self {
24            metadata: None,
25            state: Rc::new(RefCell::new(State {
26                source: Some(Box::new(source)),
27                realized: Vec::new(),
28            })),
29            offset: 0,
30        }
31    }
32    fn realize(&self, index: usize) -> bool {
33        let mut state = self.state.borrow_mut();
34        while state.realized.len() <= index {
35            let next = state.source.as_mut().and_then(Iterator::next);
36            match next {
37                Some(v) => state.realized.push(v),
38                None => {
39                    state.source = None;
40                    return false;
41                }
42            }
43        }
44        true
45    }
46    pub fn peek_first(&self) -> Option<E> {
47        self.realize(self.offset)
48            .then(|| self.state.borrow().realized[self.offset].clone())
49    }
50    pub fn pop_first(&self) -> Self {
51        Self {
52            metadata: self.metadata.clone(),
53            state: self.state.clone(),
54            offset: self.offset + usize::from(self.peek_first().is_some()),
55        }
56    }
57    pub fn count(&self) -> usize {
58        let mut state = self.state.borrow_mut();
59        while let Some(v) = state.source.as_mut().and_then(Iterator::next) {
60            state.realized.push(v)
61        }
62        state.source = None;
63        state.realized.len().saturating_sub(self.offset)
64    }
65    pub fn iter(&self) -> SeqIter<E> {
66        SeqIter {
67            seq: self.clone(),
68            index: 0,
69        }
70    }
71}
72impl<E: Clone + 'static> ICount for Seq<E> {
73    fn count(&self) -> usize {
74        Seq::count(self)
75    }
76}
77impl<E: Clone + 'static> IPeekFirst<E> for Seq<E> {
78    fn peek_first(&self) -> Option<E> {
79        Seq::peek_first(self)
80    }
81}
82impl<E: Clone + 'static> IPushFirst<E> for Seq<E> {
83    type Output = crate::lang::data::Cons<E, Self>;
84    fn push_first(&self, value: E) -> Self::Output {
85        crate::lang::data::Cons::new(value, self.clone()).with_meta(self.metadata.clone())
86    }
87}
88impl<E: Clone + 'static> ICons<E> for Seq<E> {
89    type Output = crate::lang::data::Cons<E, Self>;
90    fn cons(&self, value: E) -> Self::Output {
91        crate::lang::data::Cons::new(value, self.clone())
92    }
93}
94impl<E: Clone + 'static> IPopFirst for Seq<E> {
95    type Output = Self;
96    fn pop_first(&self) -> Self::Output {
97        Seq::pop_first(self)
98    }
99}
100impl<E: Clone + 'static> IEmpty for Seq<E> {
101    type Output = crate::lang::data::Tuple<E>;
102    fn empty(&self) -> Self::Output {
103        crate::lang::data::Tuple::Tup0.with_meta(self.metadata.clone())
104    }
105}
106impl<E: Clone + 'static> IMetadata for Seq<E> {
107    type Metadata = Rc<crate::lang::data::Metadata>;
108    fn meta(&self) -> Option<&Self::Metadata> {
109        self.metadata.as_ref()
110    }
111    fn with_meta(&self, metadata: Option<Self::Metadata>) -> Self {
112        Self {
113            metadata,
114            state: self.state.clone(),
115            offset: self.offset,
116        }
117    }
118}
119impl<E: Clone + 'static> IPersistent for Seq<E> {}
120impl<E: Clone + PartialEq + 'static> IEquality for Seq<E> {
121    fn equality(&self, other: &Self) -> bool {
122        self.clone().into_iter().eq(other.clone())
123    }
124}
125impl<E: Clone + std::fmt::Debug + 'static> IDisplay for Seq<E> {
126    fn display(&self) -> String {
127        let mut values = self.iter();
128        let mut displayed = values
129            .by_ref()
130            .take(10)
131            .map(|value| format!("{value:?}"))
132            .collect::<Vec<_>>();
133        if values.next().is_some() {
134            displayed.push("...".into());
135        }
136        format!("({})", displayed.join(" "))
137    }
138}
139impl<E: Clone + std::hash::Hash + JavaHash + 'static> IHash for Seq<E> {
140    fn hash_calc(&self, hash_type: HashType) -> u64 {
141        // Java Seq is sequential: ordered composition, "::SEQUENTIAL" seed.
142        crate::lang::hash::compose_ordered(
143            "SEQUENTIAL",
144            self.clone().into_iter().map(|v| v.java_hash(hash_type)),
145        ) as u64
146    }
147}
148impl<E: Clone + std::fmt::Debug + 'static> IObjType for Seq<E> {
149    fn obj_type(&self) -> ObjType {
150        ObjType::Sequential
151    }
152}
153impl<E: Clone + 'static> IntoIterator for Seq<E> {
154    type Item = E;
155    type IntoIter = SeqIter<E>;
156    fn into_iter(self) -> Self::IntoIter {
157        SeqIter {
158            seq: self,
159            index: 0,
160        }
161    }
162}
163
164pub struct SeqIter<E> {
165    seq: Seq<E>,
166    index: usize,
167}
168impl<E: Clone + 'static> Iterator for SeqIter<E> {
169    type Item = E;
170    fn next(&mut self) -> Option<E> {
171        let index = self.seq.offset + self.index;
172        if !self.seq.realize(index) {
173            return None;
174        }
175        self.index += 1;
176        Some(self.seq.state.borrow().realized[index].clone())
177    }
178}
179impl<E> std::fmt::Debug for Seq<E> {
180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181        f.debug_struct("Seq")
182            .field("offset", &self.offset)
183            .finish_non_exhaustive()
184    }
185}
186
187#[cfg(test)]
188mod tests {
189    use super::Seq;
190    use crate::lang::protocol::{ICons, IEmpty, IMetadata, IPopFirst, IPushFirst};
191    use std::cell::Cell;
192    use std::rc::Rc;
193    #[test]
194    fn realizes_once_and_shares_state() {
195        let calls = Rc::new(Cell::new(0));
196        let c = calls.clone();
197        let seq = Seq::new((0..3).map(move |v| {
198            c.set(c.get() + 1);
199            v
200        }));
201        assert_eq!(seq.peek_first(), Some(0));
202        assert_eq!(seq.peek_first(), Some(0));
203        assert_eq!(calls.get(), 1);
204        assert_eq!(seq.pop_first().iter().collect::<Vec<_>>(), vec![1, 2]);
205
206        let documented = seq.with_meta(Some(crate::lang::data::Metadata::document("doc")));
207        assert_eq!(
208            IPopFirst::pop_first(&documented)
209                .meta()
210                .map(|m| m.doc().unwrap()),
211            Some("doc")
212        );
213        assert!(documented.empty().is_empty());
214        assert_eq!(
215            documented.empty().meta().map(|m| m.doc().unwrap()),
216            Some("doc")
217        );
218
219        let pushed = documented.push_first(-1);
220        assert_eq!(pushed.peek_first(), &-1);
221        let tail = pushed.pop_first();
222        assert_eq!(tail.peek_first(), Some(0));
223        assert_eq!(tail.meta().map(|m| m.doc().unwrap()), Some("doc"));
224        let consed = documented.cons(-1);
225        assert_eq!(consed.meta(), None);
226        assert_eq!(consed.pop_first().peek_first(), Some(0));
227    }
228}