maybe_multiple/
multiple.rs

1// Copyright 2024 bmc::labs GmbH. All rights reserved.
2
3#[cfg(feature = "serde")]
4use serde::ser::SerializeSeq;
5
6use thiserror::Error;
7
8#[derive(Debug)]
9#[cfg_attr(
10    feature = "serde",
11    derive(serde::Deserialize),
12    serde(try_from = "Vec<T>")
13)]
14pub struct Multiple<T> {
15    head: [T; 2],
16    tail: Vec<T>,
17}
18
19////////////////////////////////////////////////////////////////////////////////
20// Type implementations
21////////////////////////////////////////////////////////////////////////////////
22
23impl<T> Multiple<T> {
24    #[allow(clippy::len_without_is_empty)] // this struct can never be empty by definition
25    pub fn len(&self) -> usize {
26        self.tail.len() + 2
27    }
28}
29
30////////////////////////////////////////////////////////////////////////////////
31// Trait implementations
32////////////////////////////////////////////////////////////////////////////////
33
34#[derive(Debug, PartialEq, Eq, Error)]
35#[error("could not convert from Vec: Vec contains fewer than 2 elements")]
36pub struct VecSizeError;
37
38impl<T> TryFrom<Vec<T>> for Multiple<T> {
39    type Error = VecSizeError;
40
41    fn try_from(v: Vec<T>) -> Result<Self, Self::Error> {
42        let mut iter = v.into_iter();
43
44        let (Some(a), Some(b)) = (iter.next(), iter.next()) else {
45            return Err(VecSizeError);
46        };
47
48        Ok(Self {
49            head: [a, b],
50            tail: iter.collect(),
51        })
52    }
53}
54
55impl<T> From<Multiple<T>> for Vec<T> {
56    fn from(m: Multiple<T>) -> Self {
57        let mut v = Vec::from(m.head);
58        v.extend(m.tail);
59        v
60    }
61}
62
63impl<T> PartialEq for Multiple<T>
64where
65    T: PartialEq,
66{
67    fn eq(&self, other: &Self) -> bool {
68        self.head == other.head && self.tail == other.tail
69    }
70}
71
72impl<T> Eq for Multiple<T> where T: Eq {}
73
74#[cfg(feature = "serde")]
75impl<T> serde::Serialize for Multiple<T>
76where
77    T: serde::Serialize,
78{
79    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80    where
81        S: serde::Serializer,
82    {
83        let mut seq = serializer.serialize_seq(Some(self.len()))?;
84        seq.serialize_element(&self.head[0])?;
85        seq.serialize_element(&self.head[1])?;
86        for t in &self.tail {
87            seq.serialize_element(t)?;
88        }
89        seq.end()
90    }
91}
92
93////////////////////////////////////////////////////////////////////////////////
94// Tests
95////////////////////////////////////////////////////////////////////////////////
96
97#[cfg(test)]
98mod tests {
99    use super::{Multiple, VecSizeError};
100    use pretty_assertions::assert_eq;
101    use proptest::collection::size_range;
102    use test_strategy::proptest;
103
104    #[test]
105    fn manual_conversions() {
106        let vec: Vec<u8> = vec![];
107        assert_eq!(Multiple::try_from(vec).unwrap_err(), VecSizeError);
108
109        let vec: Vec<u8> = vec![42];
110        assert_eq!(Multiple::try_from(vec).unwrap_err(), VecSizeError);
111
112        let vec: Vec<u8> = vec![42, 43];
113        assert_eq!(Vec::from(Multiple::try_from(vec.clone()).unwrap()), vec);
114
115        let vec: Vec<u8> = vec![42, 43, 44];
116        assert_eq!(Vec::from(Multiple::try_from(vec.clone()).unwrap()), vec);
117    }
118
119    #[proptest]
120    fn proptest_conversions(vec: Vec<u8>) {
121        if vec.len() < 2 {
122            assert_eq!(Multiple::try_from(vec).unwrap_err(), VecSizeError);
123        } else {
124            assert_eq!(Vec::from(Multiple::try_from(vec.clone()).unwrap()), vec);
125        }
126    }
127
128    #[proptest]
129    fn serialize_deserialize(#[any(size_range(2..128).lift())] vec: Vec<u8>) {
130        let multiple = Multiple::try_from(vec.clone()).unwrap();
131        assert_eq!(
132            serde_json::to_string(&multiple).unwrap(),
133            serde_json::to_string(&vec).unwrap()
134        );
135
136        let vec_str = serde_json::to_string(&vec).unwrap();
137        assert_eq!(
138            serde_json::from_str::<Multiple<_>>(&vec_str).unwrap(),
139            multiple
140        );
141    }
142}