implicit_clone/
array.rs

1use std::fmt;
2
3use super::Rc;
4use crate::ImplicitClone;
5
6/// An immutable array type inspired by [Immutable.js](https://immutable-js.com/).
7///
8/// This type is cheap to clone and thus implements [`ImplicitClone`]. It can be created based on a
9/// `&'static [T]` or based on a reference counted slice (`T`).
10#[derive(PartialEq, Eq)]
11pub enum IArray<T: ImplicitClone + 'static> {
12    /// A static slice.
13    Static(&'static [T]),
14    /// A reference counted slice.
15    Rc(Rc<[T]>),
16}
17
18// TODO add insta tests
19impl<T: fmt::Debug + ImplicitClone + 'static> fmt::Debug for IArray<T> {
20    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21        match self {
22            Self::Static(a) => a.fmt(f),
23            Self::Rc(a) => a.fmt(f),
24        }
25    }
26}
27
28impl<T: ImplicitClone + 'static> Clone for IArray<T> {
29    fn clone(&self) -> Self {
30        match self {
31            Self::Static(a) => Self::Static(a),
32            Self::Rc(a) => Self::Rc(a.clone()),
33        }
34    }
35}
36
37impl<T: ImplicitClone + 'static> Default for IArray<T> {
38    fn default() -> Self {
39        Self::Static(&[])
40    }
41}
42
43impl<T: ImplicitClone + 'static> FromIterator<T> for IArray<T> {
44    fn from_iter<I: IntoIterator<Item = T>>(it: I) -> Self {
45        let vec = it.into_iter().collect::<Vec<T>>();
46        Self::Rc(Rc::from(vec))
47    }
48}
49
50impl<T: ImplicitClone + 'static> ImplicitClone for IArray<T> {}
51
52impl<T: ImplicitClone + 'static> From<&'static [T]> for IArray<T> {
53    fn from(a: &'static [T]) -> IArray<T> {
54        IArray::Static(a)
55    }
56}
57
58impl<T: ImplicitClone + 'static> From<Vec<T>> for IArray<T> {
59    fn from(a: Vec<T>) -> IArray<T> {
60        IArray::Rc(Rc::from(a))
61    }
62}
63
64impl<T: ImplicitClone + 'static> From<Rc<[T]>> for IArray<T> {
65    fn from(a: Rc<[T]>) -> IArray<T> {
66        IArray::Rc(a)
67    }
68}
69
70impl<T: ImplicitClone + 'static> From<&IArray<T>> for IArray<T> {
71    fn from(a: &IArray<T>) -> IArray<T> {
72        a.clone()
73    }
74}
75
76impl<T: ImplicitClone + 'static> IArray<T> {
77    /// Returns a double-ended iterator over the array.
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// # use implicit_clone::unsync::*;
83    /// let x = IArray::<u8>::Static(&[1, 2, 3, 4, 5, 6]);
84    /// let mut iter = x.iter();
85    ///
86    /// assert_eq!(Some(1), iter.next());
87    /// assert_eq!(Some(6), iter.next_back());
88    /// assert_eq!(Some(5), iter.next_back());
89    /// assert_eq!(Some(2), iter.next());
90    /// assert_eq!(Some(3), iter.next());
91    /// assert_eq!(Some(4), iter.next());
92    /// assert_eq!(None, iter.next());
93    /// assert_eq!(None, iter.next_back());
94    /// ```
95    #[inline]
96    pub fn iter(&self) -> impl DoubleEndedIterator<Item = T> + '_ {
97        match self {
98            Self::Static(a) => a.iter().cloned(),
99            Self::Rc(a) => a.iter().cloned(),
100        }
101    }
102
103    /// Returns the number of elements in the vector, also referred to
104    /// as its 'length'.
105    ///
106    /// # Examples
107    ///
108    /// ```
109    /// # use implicit_clone::unsync::*;
110    /// let a = IArray::<u8>::Static(&[1, 2, 3]);
111    /// assert_eq!(a.len(), 3);
112    /// ```
113    #[inline]
114    pub fn len(&self) -> usize {
115        match self {
116            Self::Static(a) => a.len(),
117            Self::Rc(a) => a.len(),
118        }
119    }
120
121    /// Returns `true` if the vector contains no elements.
122    ///
123    /// # Examples
124    ///
125    /// ```
126    /// # use implicit_clone::unsync::*;
127    /// let v = IArray::<u8>::default();
128    /// assert!(v.is_empty());
129    ///
130    /// let v = IArray::<u8>::Static(&[1]);
131    /// assert!(!v.is_empty());
132    /// ```
133    #[inline]
134    pub fn is_empty(&self) -> bool {
135        match self {
136            Self::Static(a) => a.is_empty(),
137            Self::Rc(a) => a.is_empty(),
138        }
139    }
140
141    /// Extracts a slice containing the entire array.
142    ///
143    /// Equivalent to `&s[..]`.
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// # use implicit_clone::unsync::*;
149    /// use std::io::{self, Write};
150    /// let buffer = IArray::<u8>::Static(&[1, 2, 3, 5, 8]);
151    /// io::sink().write(buffer.as_slice()).unwrap();
152    /// ```
153    #[inline]
154    pub fn as_slice(&self) -> &[T] {
155        match self {
156            Self::Static(a) => a,
157            Self::Rc(a) => a,
158        }
159    }
160
161    /// Returns a clone of an element at a position or `None` if out of bounds.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// # use implicit_clone::unsync::*;
167    /// let v = IArray::<u8>::Static(&[10, 40, 30]);
168    /// assert_eq!(Some(40), v.get(1));
169    /// assert_eq!(None, v.get(3));
170    /// ```
171    #[inline]
172    pub fn get(&self, index: usize) -> Option<T> {
173        match self {
174            Self::Static(a) => a.get(index).cloned(),
175            Self::Rc(a) => a.get(index).cloned(),
176        }
177    }
178}
179
180impl<'a, T, U, const N: usize> PartialEq<&'a [U; N]> for IArray<T>
181where
182    T: PartialEq<U> + ImplicitClone,
183{
184    fn eq(&self, other: &&[U; N]) -> bool {
185        match self {
186            Self::Static(a) => a.eq(other),
187            Self::Rc(a) => a.eq(*other),
188        }
189    }
190}
191
192impl<T, U, const N: usize> PartialEq<[U; N]> for IArray<T>
193where
194    T: PartialEq<U> + ImplicitClone,
195{
196    fn eq(&self, other: &[U; N]) -> bool {
197        match self {
198            Self::Static(a) => a.eq(other),
199            Self::Rc(a) => a.eq(other),
200        }
201    }
202}
203
204impl<T, U> PartialEq<[U]> for IArray<T>
205where
206    T: PartialEq<U> + ImplicitClone,
207{
208    fn eq(&self, other: &[U]) -> bool {
209        match self {
210            Self::Static(a) => a.eq(&other),
211            Self::Rc(a) => a.eq(other),
212        }
213    }
214}
215
216impl<'a, T, U> PartialEq<&'a [U]> for IArray<T>
217where
218    T: PartialEq<U> + ImplicitClone,
219{
220    fn eq(&self, other: &&[U]) -> bool {
221        match self {
222            Self::Static(a) => a.eq(other),
223            Self::Rc(a) => a.eq(*other),
224        }
225    }
226}
227
228impl<T> std::ops::Deref for IArray<T>
229where
230    T: ImplicitClone,
231{
232    type Target = [T];
233
234    fn deref(&self) -> &Self::Target {
235        self.as_slice()
236    }
237}
238
239#[cfg(feature = "serde")]
240impl<T: serde::Serialize + ImplicitClone> serde::Serialize for IArray<T> {
241    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
242        <[T] as serde::Serialize>::serialize(self, serializer)
243    }
244}
245
246#[cfg(feature = "serde")]
247impl<'de, T: serde::Deserialize<'de> + ImplicitClone> serde::Deserialize<'de> for IArray<T> {
248    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
249        <Vec<T> as serde::Deserialize>::deserialize(deserializer).map(IArray::<T>::from)
250    }
251}
252
253#[cfg(test)]
254mod test_array {
255    use super::*;
256
257    #[test]
258    fn array_in_array() {
259        let array_1 = [1, 2, 3].into_iter().collect::<IArray<u32>>();
260        let array_2 = [4, 5, 6].into_iter().collect::<IArray<u32>>();
261        let array_of_array = [array_1, array_2]
262            .into_iter()
263            .collect::<IArray<IArray<u32>>>();
264        assert_eq!(array_of_array, [[1, 2, 3], [4, 5, 6]]);
265    }
266
267    #[test]
268    fn array_holding_rc_items() {
269        struct Item;
270        let _array = [Rc::new(Item)].into_iter().collect::<IArray<Rc<Item>>>();
271    }
272
273    #[test]
274    fn static_array() {
275        const _ARRAY: IArray<u32> = IArray::Static(&[1, 2, 3]);
276    }
277
278    #[test]
279    fn deref_slice() {
280        assert!(IArray::Static(&[1, 2, 3]).contains(&1));
281    }
282
283    #[test]
284    fn tuple_in_array() {
285        const _ARRAY_2: IArray<(u32, u32)> = IArray::Static(&[]);
286        const _ARRAY_5: IArray<(u32, u32, u32, u32, u32)> = IArray::Static(&[]);
287    }
288
289    #[test]
290    fn floats_in_array() {
291        const _ARRAY_F32: IArray<f32> = IArray::Static(&[]);
292        const _ARRAY_F64: IArray<f64> = IArray::Static(&[]);
293    }
294
295    #[test]
296    fn from() {
297        let x: IArray<u32> = IArray::Static(&[]);
298        let _out = IArray::from(&x);
299    }
300}