hara_native/lang/data/
seq.rs1use 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 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}