Skip to main content

hara_native/lang/data/
tuple.rs

1use crate::lang::hash::JavaHash;
2use crate::lang::protocol::{
3    HashType, IColl, IConj, ICons, ICount, IDisplay, IEmpty, IEquality, IHash, IMetadata, INth,
4    IObjType, IPeekFirst, IPeekLast, IPersistent, IPopFirst, IPopLast, IPushFirst, IPushLast,
5    ObjType,
6};
7use std::rc::Rc;
8
9#[derive(Debug, Clone)]
10pub enum Tuple<E> {
11    Tup0,
12    Tup1([E; 1]),
13    Tup2([E; 2]),
14    Tup3([E; 3]),
15    Tup4([E; 4]),
16    Tup5([E; 5]),
17    Tup6([E; 6]),
18    Tup7([E; 7]),
19    Tup8([E; 8]),
20    WithMeta(Rc<crate::lang::data::Metadata>, Box<Tuple<E>>),
21}
22
23impl<E: Clone + PartialEq> PartialEq for Tuple<E> {
24    fn eq(&self, other: &Self) -> bool {
25        self.len() == other.len() && self.iter().eq(other.iter())
26    }
27}
28impl<E: Clone + Eq> Eq for Tuple<E> {}
29impl<E: Clone + std::hash::Hash> std::hash::Hash for Tuple<E> {
30    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
31        self.iter()
32            .for_each(|value| std::hash::Hash::hash(value, state));
33    }
34}
35
36impl<E: Clone> Tuple<E> {
37    pub fn len(&self) -> usize {
38        match self {
39            Self::Tup0 => 0,
40            Self::Tup1(_) => 1,
41            Self::Tup2(_) => 2,
42            Self::Tup3(_) => 3,
43            Self::Tup4(_) => 4,
44            Self::Tup5(_) => 5,
45            Self::Tup6(_) => 6,
46            Self::Tup7(_) => 7,
47            Self::Tup8(_) => 8,
48            Self::WithMeta(_, tuple) => tuple.len(),
49        }
50    }
51    pub fn is_empty(&self) -> bool {
52        self.len() == 0
53    }
54    pub fn get(&self, index: usize) -> Option<&E> {
55        match self {
56            Self::Tup0 => None,
57            Self::Tup1(v) => v.get(index),
58            Self::Tup2(v) => v.get(index),
59            Self::Tup3(v) => v.get(index),
60            Self::Tup4(v) => v.get(index),
61            Self::Tup5(v) => v.get(index),
62            Self::Tup6(v) => v.get(index),
63            Self::Tup7(v) => v.get(index),
64            Self::Tup8(v) => v.get(index),
65            Self::WithMeta(_, tuple) => tuple.get(index),
66        }
67    }
68    pub fn iter(&self) -> impl Iterator<Item = &E> {
69        (0..self.len()).map(|i| self.get(i).expect("valid tuple index"))
70    }
71    pub fn from_values(values: Vec<E>) -> Result<Self, String> {
72        Ok(match values.as_slice() {
73            [] => Self::Tup0,
74            [a] => Self::Tup1([a.clone()]),
75            [a, b] => Self::Tup2([a.clone(), b.clone()]),
76            [a, b, c] => Self::Tup3([a.clone(), b.clone(), c.clone()]),
77            [a, b, c, d] => Self::Tup4([a.clone(), b.clone(), c.clone(), d.clone()]),
78            [a, b, c, d, e] => Self::Tup5([a.clone(), b.clone(), c.clone(), d.clone(), e.clone()]),
79            [a, b, c, d, e, f] => Self::Tup6([
80                a.clone(),
81                b.clone(),
82                c.clone(),
83                d.clone(),
84                e.clone(),
85                f.clone(),
86            ]),
87            [a, b, c, d, e, f, g] => Self::Tup7([
88                a.clone(),
89                b.clone(),
90                c.clone(),
91                d.clone(),
92                e.clone(),
93                f.clone(),
94                g.clone(),
95            ]),
96            [a, b, c, d, e, f, g, h] => Self::Tup8([
97                a.clone(),
98                b.clone(),
99                c.clone(),
100                d.clone(),
101                e.clone(),
102                f.clone(),
103                g.clone(),
104                h.clone(),
105            ]),
106            _ => return Err("tuple arity cannot exceed 8".into()),
107        })
108    }
109    pub fn push_first(&self, value: E) -> Result<Self, String> {
110        Self::from_values(std::iter::once(value).chain(self.iter().cloned()).collect())
111            .map(|tuple| tuple.with_meta(self.meta().cloned()))
112    }
113    pub fn push_last(&self, value: E) -> Result<Self, String> {
114        Self::from_values(self.iter().cloned().chain(std::iter::once(value)).collect())
115            .map(|tuple| tuple.with_meta(self.meta().cloned()))
116    }
117    pub fn pop_first(&self) -> Self {
118        Self::from_values(self.iter().skip(1).cloned().collect())
119            .expect("smaller tuple")
120            .with_meta(self.meta().cloned())
121    }
122    pub fn pop_last(&self) -> Self {
123        Self::from_values(
124            self.iter()
125                .take(self.len().saturating_sub(1))
126                .cloned()
127                .collect(),
128        )
129        .expect("smaller tuple")
130        .with_meta(self.meta().cloned())
131    }
132    pub fn peek_first(&self) -> Option<&E> {
133        self.get(0)
134    }
135    pub fn peek_last(&self) -> Option<&E> {
136        self.len().checked_sub(1).and_then(|i| self.get(i))
137    }
138}
139impl<E: Clone> ICount for Tuple<E> {
140    fn count(&self) -> usize {
141        self.len()
142    }
143}
144impl<E: Clone> INth<E> for Tuple<E> {
145    fn nth(&self, index: usize) -> Option<&E> {
146        self.get(index)
147    }
148}
149impl<E: Clone> IPeekFirst<E> for Tuple<E> {
150    fn peek_first(&self) -> Option<E> {
151        Tuple::peek_first(self).cloned()
152    }
153}
154impl<E: Clone> IPeekLast<E> for Tuple<E> {
155    fn peek_last(&self) -> Option<E> {
156        Tuple::peek_last(self).cloned()
157    }
158}
159impl<E: Clone> IPushFirst<E> for Tuple<E> {
160    type Output = Self;
161    fn push_first(&self, value: E) -> Self {
162        Tuple::push_first(self, value).expect("tuple arity cannot exceed 8")
163    }
164}
165impl<E: Clone> IPushLast<E> for Tuple<E> {
166    type Output = Self;
167    fn push_last(&self, value: E) -> Self {
168        Tuple::push_last(self, value).expect("tuple arity cannot exceed 8")
169    }
170}
171impl<E: Clone> IPopFirst for Tuple<E> {
172    type Output = Self;
173    fn pop_first(&self) -> Self {
174        Tuple::pop_first(self)
175    }
176}
177impl<E: Clone> IPopLast for Tuple<E> {
178    type Output = Self;
179    fn pop_last(&self) -> Self {
180        Tuple::pop_last(self)
181    }
182}
183impl<E: Clone> ICons<E> for Tuple<E> {
184    type Output = Self;
185    fn cons(&self, value: E) -> Self {
186        IPushFirst::push_first(self, value)
187    }
188}
189impl<E: Clone> IConj<E> for Tuple<E> {
190    type Output = Self;
191    fn conj(&self, value: E) -> Self {
192        IPushLast::push_last(self, value)
193    }
194}
195impl<E: Clone> IPersistent for Tuple<E> {}
196impl<E: Clone> IMetadata for Tuple<E> {
197    type Metadata = Rc<crate::lang::data::Metadata>;
198    fn meta(&self) -> Option<&Self::Metadata> {
199        match self {
200            Self::WithMeta(metadata, _) => Some(metadata),
201            _ => None,
202        }
203    }
204    fn with_meta(&self, metadata: Option<Self::Metadata>) -> Self {
205        let base = match self {
206            Self::WithMeta(_, tuple) => tuple.as_ref(),
207            _ => self,
208        };
209        metadata.map_or_else(
210            || base.clone(),
211            |metadata| Self::WithMeta(metadata, Box::new(base.clone())),
212        )
213    }
214}
215impl<E: Clone> IEmpty for Tuple<E> {
216    type Output = Self;
217    fn empty(&self) -> Self::Output {
218        Self::Tup0.with_meta(self.meta().cloned())
219    }
220}
221impl<E: Clone> Default for Tuple<E> {
222    fn default() -> Self {
223        Self::Tup0
224    }
225}
226
227impl<E: Clone> IntoIterator for Tuple<E> {
228    type Item = E;
229    type IntoIter = std::vec::IntoIter<E>;
230    fn into_iter(self) -> Self::IntoIter {
231        self.iter().cloned().collect::<Vec<_>>().into_iter()
232    }
233}
234impl<E: Clone + PartialEq> IEquality for Tuple<E> {
235    fn equality(&self, other: &Self) -> bool {
236        self == other
237    }
238}
239impl<E: Clone + std::fmt::Debug> IDisplay for Tuple<E> {
240    fn display(&self) -> String {
241        format!(
242            "[{}]",
243            self.iter()
244                .map(|v| format!("{v:?}"))
245                .collect::<Vec<_>>()
246                .join(" ")
247        )
248    }
249}
250impl<E: Clone + std::hash::Hash + JavaHash> IHash for Tuple<E> {
251    fn hash_calc(&self, hash_type: HashType) -> u64 {
252        // Java Tuple.TupN implements ISequential: ordered composition,
253        // "::SEQUENTIAL" seed — NOT "::TUPLE" (see lang::hash). MapEntry
254        // values use this same ordered two-value composition.
255        crate::lang::hash::compose_ordered(
256            "SEQUENTIAL",
257            self.iter().map(|value| value.java_hash(hash_type)),
258        ) as u64
259    }
260}
261impl<E: Clone + std::fmt::Debug> IObjType for Tuple<E> {
262    fn obj_type(&self) -> ObjType {
263        ObjType::Sequential
264    }
265}
266impl<E> IColl<E> for Tuple<E>
267where
268    E: Clone + PartialEq + std::fmt::Debug + std::hash::Hash + JavaHash,
269{
270    fn start_string(&self) -> &'static str {
271        "["
272    }
273    fn end_string(&self) -> &'static str {
274        "]"
275    }
276}
277
278#[cfg(test)]
279mod tests {
280    use super::Tuple;
281    use crate::lang::protocol::{IEmpty, IMetadata};
282
283    #[test]
284    fn covers_all_java_arities_and_linear_operations() {
285        let mut t = Tuple::Tup0;
286        for i in 0..8 {
287            t = t.push_last(i).unwrap();
288            assert_eq!(t.len(), i + 1)
289        }
290        assert!(t.push_last(8).is_err());
291        assert_eq!(t.peek_first(), Some(&0));
292        assert_eq!(t.peek_last(), Some(&7));
293        assert_eq!(t.pop_first().peek_first(), Some(&1));
294        assert_eq!(t.pop_last().peek_last(), Some(&6));
295    }
296
297    #[test]
298    fn preserves_metadata_across_persistent_operations() {
299        let tuple =
300            Tuple::Tup2([1, 2]).with_meta(Some(crate::lang::data::Metadata::document("doc")));
301
302        for result in [
303            tuple.push_first(0).unwrap(),
304            tuple.push_last(3).unwrap(),
305            tuple.pop_first(),
306            tuple.pop_last(),
307            tuple.empty(),
308        ] {
309            assert_eq!(result.meta().map(|m| m.doc().unwrap()), Some("doc"));
310        }
311        assert_eq!(tuple.push_first(0).unwrap().len(), 3);
312        assert_eq!(tuple.empty().len(), 0);
313    }
314}