kast_util/
tuple.rs

1use std::collections::BTreeMap;
2use std::fmt::Write;
3
4use try_hash::TryHash;
5
6#[derive(Debug, Clone)]
7pub struct Tuple<T> {
8    unnamed: Vec<T>,
9    named: BTreeMap<String, T>,
10    named_order: Vec<String>,
11}
12
13impl<T: PartialEq> PartialEq for Tuple<T> {
14    fn eq(&self, other: &Self) -> bool {
15        self.unnamed == other.unnamed && self.named == other.named
16    }
17}
18
19impl<T: Eq> Eq for Tuple<T> {}
20
21impl<T: PartialOrd> PartialOrd for Tuple<T> {
22    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
23        match self.unnamed.partial_cmp(&other.unnamed) {
24            Some(core::cmp::Ordering::Equal) => {}
25            ord => return ord,
26        }
27        self.named.partial_cmp(&other.named)
28    }
29}
30
31impl<T: Ord> Ord for Tuple<T> {
32    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
33        match self.unnamed.cmp(&other.unnamed) {
34            core::cmp::Ordering::Equal => {}
35            ord => return ord,
36        }
37        self.named.cmp(&other.named)
38    }
39}
40
41impl<T: std::hash::Hash> std::hash::Hash for Tuple<T> {
42    fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
43        for unnamed in &self.unnamed {
44            unnamed.hash(hasher);
45        }
46        for (name, value) in &self.named {
47            std::hash::Hash::hash(name, hasher);
48            value.hash(hasher);
49        }
50    }
51}
52
53impl<T: TryHash> TryHash for Tuple<T> {
54    type Error = T::Error;
55    fn try_hash(&self, hasher: &mut impl std::hash::Hasher) -> Result<(), Self::Error> {
56        for unnamed in &self.unnamed {
57            unnamed.try_hash(hasher)?;
58        }
59        for (name, value) in &self.named {
60            std::hash::Hash::hash(name, hasher);
61            value.try_hash(hasher)?;
62        }
63        Ok(())
64    }
65}
66
67impl<T> Tuple<T> {
68    pub fn empty() -> Self {
69        Self {
70            unnamed: vec![],
71            named: BTreeMap::new(),
72            named_order: vec![],
73        }
74    }
75    pub fn single_named(name: impl Into<String>, value: T) -> Self {
76        let mut result = Self::empty();
77        result.add_named(name, value);
78        result
79    }
80    pub fn is_empty(&self) -> bool {
81        self.unnamed.is_empty() && self.named.is_empty()
82    }
83    pub fn get_unnamed(&self) -> &[T] {
84        &self.unnamed
85    }
86    pub fn get_named(&self, name: &str) -> Option<&T> {
87        self.named.get(name)
88    }
89    pub fn take_named(&mut self, name: &str) -> Option<T> {
90        let value = self.named.remove(name);
91        if value.is_some() {
92            self.named_order.retain(|s| s != name);
93        }
94        value
95    }
96    pub fn add_unnamed(&mut self, value: T) {
97        self.unnamed.push(value);
98    }
99    pub fn add_named(&mut self, name: impl Into<String>, value: T) {
100        let name: String = name.into();
101        if self.named.insert(name.clone(), value).is_none() {
102            self.named_order.push(name.clone());
103        }
104    }
105    pub fn add(&mut self, name: Option<String>, value: T) {
106        match name {
107            Some(name) => self.add_named(name, value),
108            None => self.add_unnamed(value),
109        }
110    }
111    pub fn fmt_with_name<'a>(&'a self, name: &'a str) -> NamedTupleFmt<'a, T> {
112        NamedTupleFmt { name, tuple: self }
113    }
114    pub fn unnamed(&self) -> impl Iterator<Item = &T> + '_ {
115        self.unnamed.iter()
116    }
117    pub fn named(&self) -> impl Iterator<Item = (&str, &T)> + '_ {
118        self.named_order
119            .iter()
120            .map(|key| (key.as_str(), &self.named[key]))
121    }
122    pub fn into_field_values(mut self) -> impl Iterator<Item = T> {
123        self.unnamed.into_iter().chain(
124            self.named_order
125                .into_iter()
126                .map(move |name| self.named.remove(&name).unwrap()),
127        )
128    }
129    pub fn show_fields(&self) -> impl std::fmt::Display + '_ {
130        struct ShowFields<'a, T>(&'a Tuple<T>);
131        impl<T> std::fmt::Display for ShowFields<'_, T> {
132            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133                let mut first = true;
134                if !self.0.unnamed.is_empty() {
135                    write!(f, "{} unnamed fields", self.0.unnamed.len())?;
136                    first = false;
137                }
138                for name in &self.0.named_order {
139                    if first {
140                        first = false;
141                    } else {
142                        write!(f, ", ")?;
143                    }
144                    write!(f, "{name:?}")?;
145                }
146                Ok(())
147            }
148        }
149        ShowFields(self)
150    }
151    pub fn as_ref(&self) -> Tuple<&T> {
152        Tuple {
153            unnamed: self.unnamed.iter().collect(),
154            named: self
155                .named
156                .iter()
157                .map(|(key, value)| (key.clone(), value))
158                .collect(),
159            named_order: self.named_order.clone(),
160        }
161    }
162    pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Tuple<U> {
163        Tuple {
164            unnamed: self.unnamed.into_iter().map(&mut f).collect(),
165            named: self
166                .named
167                .into_iter()
168                .map(|(key, value)| (key, f(value)))
169                .collect(),
170            named_order: self.named_order,
171        }
172    }
173    pub fn values(&self) -> impl Iterator<Item = &T> + '_ {
174        self.unnamed
175            .iter()
176            .chain(self.named_order.iter().map(|name| &self.named[name]))
177    }
178}
179
180pub struct TupleIntoIter<T> {
181    unnamed: <Vec<T> as IntoIterator>::IntoIter,
182    names: <Vec<String> as IntoIterator>::IntoIter,
183    named: BTreeMap<String, T>,
184}
185
186impl<T> Iterator for TupleIntoIter<T> {
187    type Item = (Option<String>, T);
188    fn next(&mut self) -> Option<Self::Item> {
189        if let Some(value) = self.unnamed.next() {
190            return Some((None, value));
191        }
192        let name = self.names.next()?;
193        let value = self.named.remove(&name).unwrap();
194        Some((Some(name), value))
195    }
196}
197
198impl<T> IntoIterator for Tuple<T> {
199    type Item = (Option<String>, T);
200    type IntoIter = TupleIntoIter<T>;
201    fn into_iter(self) -> Self::IntoIter {
202        TupleIntoIter {
203            unnamed: self.unnamed.into_iter(),
204            names: self.named_order.into_iter(),
205            named: self.named,
206        }
207    }
208}
209
210#[derive(Debug, thiserror::Error)]
211pub enum IntoFixedErrorReason {
212    IncorrectAmountOfUnnamedFields { expected: usize, actual: usize },
213    NamedFieldNotPresent(String),
214    NamedFieldUnexpected(String),
215}
216
217impl std::fmt::Display for IntoFixedErrorReason {
218    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219        match self {
220            Self::NamedFieldNotPresent(name) => {
221                write!(f, "field {name:?} is not present")
222            }
223            Self::NamedFieldUnexpected(name) => {
224                write!(f, "field {name:?} was not expected")
225            }
226            Self::IncorrectAmountOfUnnamedFields { expected, actual } => {
227                write!(f, "expected {expected} unnamed fields, got {actual}")
228            }
229        }
230    }
231}
232
233#[derive(Debug, thiserror::Error)]
234pub struct IntoFixedError {
235    erased_value: Tuple<()>,
236    expected_unnamed_fields: usize,
237    expected_named_fields: Vec<String>,
238    optional_fields: Vec<String>,
239    #[source]
240    reason: IntoFixedErrorReason,
241}
242
243impl std::fmt::Display for IntoFixedError {
244    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245        write!(f, "expected ")?;
246        let mut started = false;
247        let mut start = |f: &mut std::fmt::Formatter| {
248            if started {
249                write!(f, ", ")
250            } else {
251                started = true;
252                Ok(())
253            }
254        };
255        if self.expected_unnamed_fields != 0 {
256            start(f)?;
257            write!(f, "{} unnamed fields", self.expected_unnamed_fields)?;
258        }
259        for name in &self.expected_named_fields {
260            start(f)?;
261            write!(f, "{name:?}")?;
262        }
263        if !self.optional_fields.is_empty() {
264            start(f)?;
265            write!(f, "optional ")?;
266            for (i, name) in self.optional_fields.iter().enumerate() {
267                if i != 0 {
268                    write!(f, ", ")?;
269                }
270                write!(f, "{name:?}")?;
271            }
272        }
273        write!(f, " but got {}", self.erased_value.show_fields())
274    }
275}
276
277pub struct FixedTuple<const UNNAMED: usize, const NAMED: usize, const OPTIONAL: usize, T> {
278    unnamed: [T; UNNAMED],
279    named: [T; NAMED],
280    optional: [Option<T>; OPTIONAL],
281}
282
283impl<T> Tuple<T> {
284    pub fn into_fixed<const UNNAMED: usize, const NAMED: usize, const OPTIONAL: usize>(
285        mut self,
286        named: [&str; NAMED],
287        optional: [&str; OPTIONAL],
288    ) -> Result<FixedTuple<UNNAMED, NAMED, OPTIONAL, T>, IntoFixedError> {
289        let erased_value = self.as_ref().map(|_| ());
290        macro_rules! error {
291            ($reason:expr) => {
292                Err(IntoFixedError {
293                    expected_unnamed_fields: UNNAMED,
294                    expected_named_fields: named.iter().map(|s| s.to_string()).collect(),
295                    optional_fields: optional.iter().map(|s| s.to_string()).collect(),
296                    reason: $reason,
297                    erased_value,
298                })
299            };
300        }
301
302        if self.unnamed.len() != UNNAMED {
303            return error!(IntoFixedErrorReason::IncorrectAmountOfUnnamedFields {
304                expected: UNNAMED,
305                actual: self.unnamed.len()
306            });
307        }
308        let unnamed: [T; UNNAMED] = self.unnamed.try_into().ok().unwrap();
309
310        if let Some(name) = self
311            .named_order
312            .iter()
313            .find(|name| !named.contains(&name.as_str()) && !optional.contains(&name.as_str()))
314        {
315            return error!(IntoFixedErrorReason::NamedFieldUnexpected(name.to_string()));
316        }
317
318        if let Some(name) = named.iter().find(|&&name| !self.named.contains_key(name)) {
319            return error!(IntoFixedErrorReason::NamedFieldNotPresent(name.to_string()));
320        }
321
322        let named = named.map(|name| self.named.remove(name).unwrap());
323        let optional = optional.map(|name| self.named.remove(name));
324
325        Ok(FixedTuple {
326            unnamed,
327            named,
328            optional,
329        })
330    }
331    /// let [a, b, c] = tuple.into_unnamed()
332    pub fn into_unnamed<const N: usize>(self) -> Result<[T; N], IntoFixedError> {
333        Ok(self.into_fixed([], [])?.unnamed)
334    }
335    pub fn into_named_opt<const N: usize, const OPT: usize>(
336        self,
337        names: [&str; N],
338        optional: [&str; OPT],
339    ) -> Result<([T; N], [Option<T>; OPT]), IntoFixedError> {
340        let FixedTuple {
341            unnamed: [],
342            named,
343            optional,
344        } = self.into_fixed(names, optional)?;
345        Ok((named, optional))
346    }
347    pub fn into_named<const N: usize>(self, names: [&str; N]) -> Result<[T; N], IntoFixedError> {
348        Ok(self.into_fixed::<0, N, 0>(names, [])?.named)
349    }
350    pub fn into_single_named(self, name: &str) -> Result<T, IntoFixedError> {
351        self.into_named([name]).map(|[value]| value)
352    }
353}
354
355#[derive(Debug, thiserror::Error)]
356pub enum TupleZipError {
357    #[error("different amount of unnamed fields: {0} vs {1}")]
358    DifferentUnnamedAmount(usize, usize),
359    #[error("field {0} not present in other")]
360    NamedNotPresentInOther(String),
361    #[error("field {0} is only present in other")]
362    NamedOnlyPresentInOther(String),
363}
364
365impl<T> Tuple<T> {
366    pub fn zip<U>(mut self, mut other: Tuple<U>) -> Result<Tuple<(T, U)>, TupleZipError> {
367        if self.unnamed.len() != other.unnamed.len() {
368            return Err(TupleZipError::DifferentUnnamedAmount(
369                self.unnamed.len(),
370                other.unnamed.len(),
371            ));
372        }
373        for name in self.named.keys() {
374            if !other.named.contains_key(name) {
375                return Err(TupleZipError::NamedNotPresentInOther(name.to_owned()));
376            }
377        }
378        for name in other.named.keys() {
379            if !self.named.contains_key(name) {
380                return Err(TupleZipError::NamedOnlyPresentInOther(name.to_owned()));
381            }
382        }
383        Ok(Tuple {
384            unnamed: self.unnamed.into_iter().zip(other.unnamed).collect(),
385            named: self
386                .named_order
387                .iter()
388                .map(|name| {
389                    (
390                        name.to_owned(),
391                        (
392                            self.named.remove(name).unwrap(),
393                            other.named.remove(name).unwrap(),
394                        ),
395                    )
396                })
397                .collect(),
398            named_order: self.named_order,
399        })
400    }
401}
402
403impl<T: std::fmt::Display> std::fmt::Display for Tuple<T> {
404    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
405        write!(f, "(")?;
406        {
407            if !self.is_empty() {
408                writeln!(f)?;
409            }
410            let mut f = pad_adapter::PadAdapter::new(f);
411            for field in &self.unnamed {
412                writeln!(f, "{field},")?;
413            }
414            for name in &self.named_order {
415                let field = &self.named[name];
416                writeln!(f, ".{name} = {field},")?;
417            }
418        }
419        write!(f, ")")?;
420        Ok(())
421    }
422}
423
424pub struct NamedTupleFmt<'a, T> {
425    name: &'a str,
426    tuple: &'a Tuple<T>,
427}
428
429impl<T: std::fmt::Display> std::fmt::Display for NamedTupleFmt<'_, T> {
430    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
431        write!(f, "{} {}", self.name, self.tuple)
432    }
433}