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 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}