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///
11/// Since `IArray<T>` is an immutable data structure, direct modifications like adding or removing
12/// elements are not possible. To make changes, you need to convert it into a `Vec<T>` using
13/// `.to_vec()`, modify the vector, and then convert it back into an `IArray<T>` using
14/// `IArray::from`. Here's an example demonstrating this approach:
15///
16/// ```rust
17/// # use implicit_clone::unsync::*;
18/// let iarray = IArray::from(vec![1, 2, 3]);
19///
20/// // Convert to Vec, modify it, then convert back to IArray
21/// let mut vec = iarray.to_vec();
22/// vec.push(4);
23/// vec.retain(|&x| x != 2); // Remove the element `2`
24/// let new_iarray = IArray::from(vec);
25///
26/// assert_eq!(new_iarray, IArray::from(vec![1, 3, 4]));
27/// ```
28///
29/// This ensures that you can work with a mutable `Vec<T>` while still benefiting from
30/// `IArray<T>`'s immutable properties when needed.
31#[derive(PartialEq, Eq)]
32pub enum IArray<T: ImplicitClone + 'static> {
33    /// A static slice.
34    Static(&'static [T]),
35    /// A reference counted slice.
36    Rc(Rc<[T]>),
37}
38
39// TODO add insta tests
40impl<T: fmt::Debug + ImplicitClone + 'static> fmt::Debug for IArray<T> {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        match self {
43            Self::Static(a) => a.fmt(f),
44            Self::Rc(a) => a.fmt(f),
45        }
46    }
47}
48
49impl<T: ImplicitClone + 'static> Clone for IArray<T> {
50    fn clone(&self) -> Self {
51        match self {
52            Self::Static(a) => Self::Static(a),
53            Self::Rc(a) => Self::Rc(a.clone()),
54        }
55    }
56}
57
58impl<T: ImplicitClone + 'static> Default for IArray<T> {
59    fn default() -> Self {
60        Self::EMPTY
61    }
62}
63
64impl<T: ImplicitClone + 'static> FromIterator<T> for IArray<T> {
65    fn from_iter<I: IntoIterator<Item = T>>(it: I) -> Self {
66        let mut it = it.into_iter();
67        match it.size_hint() {
68            (_, Some(0)) => Self::EMPTY,
69            (_, Some(1)) => {
70                if let Some(element) = it.next() {
71                    Self::from([element])
72                } else {
73                    Self::EMPTY
74                }
75            }
76            _ => Self::Rc(Rc::from_iter(it)),
77        }
78    }
79}
80
81impl<T: ImplicitClone + 'static> ImplicitClone for IArray<T> {}
82
83impl<T: ImplicitClone + 'static> From<&'static [T]> for IArray<T> {
84    fn from(a: &'static [T]) -> IArray<T> {
85        IArray::Static(a)
86    }
87}
88
89impl<T: ImplicitClone + 'static> From<Vec<T>> for IArray<T> {
90    fn from(a: Vec<T>) -> IArray<T> {
91        IArray::Rc(Rc::from(a))
92    }
93}
94
95impl<T: ImplicitClone + 'static> From<Rc<[T]>> for IArray<T> {
96    fn from(a: Rc<[T]>) -> IArray<T> {
97        IArray::Rc(a)
98    }
99}
100
101impl<T: ImplicitClone + 'static> From<&IArray<T>> for IArray<T> {
102    fn from(a: &IArray<T>) -> IArray<T> {
103        a.clone()
104    }
105}
106
107impl<T: ImplicitClone + 'static, const N: usize> From<[T; N]> for IArray<T> {
108    fn from(a: [T; N]) -> IArray<T> {
109        IArray::Rc(Rc::from(a))
110    }
111}
112
113/// An iterator over the cloned elements of an `IArray`.
114#[derive(Debug)]
115pub struct IArrayIntoIter<T: ImplicitClone + 'static> {
116    array: IArray<T>,
117    left: usize,
118    right: usize,
119}
120
121impl<T: ImplicitClone + 'static> IntoIterator for IArray<T> {
122    type Item = T;
123    type IntoIter = IArrayIntoIter<T>;
124
125    fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
126        IArrayIntoIter {
127            left: 0,
128            right: self.len(),
129            array: self,
130        }
131    }
132}
133
134impl<T: ImplicitClone + 'static> Iterator for IArrayIntoIter<T> {
135    type Item = T;
136
137    fn next(&mut self) -> Option<Self::Item> {
138        if self.left >= self.right {
139            return None;
140        }
141        let item = &self.array[self.left];
142        self.left += 1;
143        Some(item.clone())
144    }
145}
146
147impl<T: ImplicitClone + 'static> DoubleEndedIterator for IArrayIntoIter<T> {
148    fn next_back(&mut self) -> Option<Self::Item> {
149        if self.left >= self.right {
150            return None;
151        }
152        self.right -= 1;
153        Some(self.array[self.right].clone())
154    }
155}
156
157impl<T: ImplicitClone + 'static> IArray<T> {
158    /// An empty array without allocation.
159    pub const EMPTY: Self = Self::Static(&[]);
160
161    /// Returns the number of elements in the vector, also referred to
162    /// as its 'length'.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// # use implicit_clone::unsync::*;
168    /// let a = IArray::<u8>::Static(&[1, 2, 3]);
169    /// assert_eq!(a.len(), 3);
170    /// ```
171    #[inline]
172    pub fn len(&self) -> usize {
173        match self {
174            Self::Static(a) => a.len(),
175            Self::Rc(a) => a.len(),
176        }
177    }
178
179    /// Returns `true` if the vector contains no elements.
180    ///
181    /// # Examples
182    ///
183    /// ```
184    /// # use implicit_clone::unsync::*;
185    /// let v = IArray::<u8>::default();
186    /// assert!(v.is_empty());
187    ///
188    /// let v = IArray::<u8>::Static(&[1]);
189    /// assert!(!v.is_empty());
190    /// ```
191    #[inline]
192    pub fn is_empty(&self) -> bool {
193        match self {
194            Self::Static(a) => a.is_empty(),
195            Self::Rc(a) => a.is_empty(),
196        }
197    }
198
199    /// Extracts a slice containing the entire array.
200    ///
201    /// Equivalent to `&s[..]`.
202    ///
203    /// # Examples
204    ///
205    /// ```
206    /// # use implicit_clone::unsync::*;
207    /// use std::io::{self, Write};
208    /// let buffer = IArray::<u8>::Static(&[1, 2, 3, 5, 8]);
209    /// io::sink().write(buffer.as_slice()).unwrap();
210    /// ```
211    #[inline]
212    pub fn as_slice(&self) -> &[T] {
213        match self {
214            Self::Static(a) => a,
215            Self::Rc(a) => a,
216        }
217    }
218
219    /// Returns a reference of an element at a position or `None` if out of bounds.
220    ///
221    /// # Examples
222    ///
223    /// ```
224    /// # use implicit_clone::unsync::*;
225    /// let v = IArray::<u8>::Static(&[10, 40, 30]);
226    /// assert_eq!(Some(&40), v.get(1));
227    /// assert_eq!(None, v.get(3));
228    /// ```
229    #[inline]
230    pub fn get(&self, index: usize) -> Option<&T> {
231        match self {
232            Self::Static(a) => a.get(index),
233            Self::Rc(a) => a.get(index),
234        }
235    }
236
237    /// Gets a mutable reference into the array, if there are no other references.
238    ///
239    /// If this array is an `Rc` with no other strong or weak references, returns
240    /// a mutable slice of the contained data without any cloning. Otherwise returns
241    /// `None`.
242    ///
243    /// # Example
244    ///
245    /// ```
246    /// # use implicit_clone::unsync::*;
247    /// # use std::rc::Rc;
248    /// // This will reuse the Rc storage
249    /// let mut v1 = IArray::<u8>::Rc(Rc::new([1,2,3]));
250    /// v1.get_mut().unwrap()[1] = 123;
251    /// assert_eq!(&[1,123,3], v1.as_slice());
252    ///
253    /// // Another reference will prevent exclusive access
254    /// let v2 = v1.clone();
255    /// assert!(v1.get_mut().is_none());
256    ///
257    /// // Static references are immutable
258    /// let mut v3 = IArray::<u8>::Static(&[1,2,3]);
259    /// assert!(v3.get_mut().is_none());
260    /// ```
261    #[inline]
262    pub fn get_mut(&mut self) -> Option<&mut [T]> {
263        match self {
264            Self::Rc(ref mut rc) => Rc::get_mut(rc),
265            Self::Static(_) => None,
266        }
267    }
268
269    /// Makes a mutable reference into the array.
270    ///
271    /// If this array is an `Rc` with no other strong or weak references, returns
272    /// a mutable slice of the contained data without any cloning. Otherwise, it clones the
273    /// data into a new array and returns a mutable slice into that.
274    ///
275    /// If this array is a `Static`, it clones its elements into a new `Rc` array and returns a
276    /// mutable slice into that new array.
277    ///
278    /// # Examples
279    ///
280    /// ```
281    /// # use implicit_clone::unsync::*;
282    /// // This will reuse the Rc storage
283    /// let mut data = IArray::<u8>::from(vec![1,2,3]);
284    /// data.make_mut()[1] = 123;
285    /// assert_eq!(&[1,123,3], data.as_slice());
286    /// assert!(matches!(data, IArray::<u8>::Rc(_)));
287    /// ```
288    ///
289    /// ```
290    /// # use implicit_clone::unsync::*;
291    /// // This will create a new copy
292    /// let mut data = IArray::<u8>::from(vec![1,2,3]);
293    /// let other_data = data.clone();
294    /// data.make_mut()[1] = 123;
295    /// assert_eq!(&[1,123,3], data.as_slice());
296    /// assert_eq!(&[1,2,3], other_data.as_slice());
297    /// assert!(matches!(data, IArray::<u8>::Rc(_)));
298    /// assert!(matches!(other_data, IArray::<u8>::Rc(_)));
299    /// ```
300    ///
301    /// ```
302    /// # use implicit_clone::unsync::*;
303    /// // This will create a new copy
304    /// let mut data = IArray::<u8>::Static(&[1,2,3]);
305    /// let other_data = data.clone();
306    /// data.make_mut()[1] = 123;
307    /// assert_eq!(&[1,123,3], data.as_slice());
308    /// assert_eq!(&[1,2,3], other_data.as_slice());
309    /// assert!(matches!(data, IArray::<u8>::Rc(_)));
310    /// assert!(matches!(other_data, IArray::<u8>::Static(_)));
311    /// ```
312    #[inline]
313    pub fn make_mut(&mut self) -> &mut [T] {
314        match self {
315            Self::Rc(ref mut rc) => {
316                // This code is somewhat weirdly written to work around
317                // https://github.com/rust-lang/rust/issues/54663 - we can't just check if this is
318                // an Rc with one reference with get_mut in an if branch and copy otherwise, since
319                // returning the mutable slice extends its lifetime for the rest of the function.
320                if Rc::get_mut(rc).is_none() {
321                    *rc = rc.iter().cloned().collect::<Rc<[T]>>();
322                }
323                Rc::get_mut(rc).unwrap()
324            }
325            Self::Static(slice) => {
326                *self = Self::Rc(slice.iter().cloned().collect());
327                match self {
328                    Self::Rc(rc) => Rc::get_mut(rc).unwrap(),
329                    _ => unreachable!(),
330                }
331            }
332        }
333    }
334}
335
336impl<'a, T, U, const N: usize> PartialEq<&'a [U; N]> for IArray<T>
337where
338    T: PartialEq<U> + ImplicitClone,
339{
340    fn eq(&self, other: &&[U; N]) -> bool {
341        match self {
342            Self::Static(a) => a.eq(other),
343            Self::Rc(a) => a.eq(*other),
344        }
345    }
346}
347
348impl<T, U, const N: usize> PartialEq<[U; N]> for IArray<T>
349where
350    T: PartialEq<U> + ImplicitClone,
351{
352    fn eq(&self, other: &[U; N]) -> bool {
353        match self {
354            Self::Static(a) => a.eq(other),
355            Self::Rc(a) => a.eq(other),
356        }
357    }
358}
359
360impl<T, U> PartialEq<[U]> for IArray<T>
361where
362    T: PartialEq<U> + ImplicitClone,
363{
364    fn eq(&self, other: &[U]) -> bool {
365        match self {
366            Self::Static(a) => a.eq(&other),
367            Self::Rc(a) => a.eq(other),
368        }
369    }
370}
371
372impl<'a, T, U> PartialEq<&'a [U]> for IArray<T>
373where
374    T: PartialEq<U> + ImplicitClone,
375{
376    fn eq(&self, other: &&[U]) -> bool {
377        match self {
378            Self::Static(a) => a.eq(other),
379            Self::Rc(a) => a.eq(*other),
380        }
381    }
382}
383
384impl<T> std::ops::Deref for IArray<T>
385where
386    T: ImplicitClone,
387{
388    type Target = [T];
389
390    fn deref(&self) -> &Self::Target {
391        self.as_slice()
392    }
393}
394
395#[cfg(feature = "serde")]
396impl<T: serde::Serialize + ImplicitClone> serde::Serialize for IArray<T> {
397    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
398        <[T] as serde::Serialize>::serialize(self, serializer)
399    }
400}
401
402#[cfg(feature = "serde")]
403impl<'de, T: serde::Deserialize<'de> + ImplicitClone> serde::Deserialize<'de> for IArray<T> {
404    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
405        <Vec<T> as serde::Deserialize>::deserialize(deserializer).map(IArray::<T>::from)
406    }
407}
408
409#[cfg(test)]
410mod test_array {
411    use super::*;
412
413    #[test]
414    fn array_in_array() {
415        let array_1 = [1, 2, 3].into_iter().collect::<IArray<u32>>();
416        let array_2 = [4, 5, 6].into_iter().collect::<IArray<u32>>();
417        let array_of_array = [array_1, array_2]
418            .into_iter()
419            .collect::<IArray<IArray<u32>>>();
420        assert_eq!(array_of_array, [[1, 2, 3], [4, 5, 6]]);
421    }
422
423    #[test]
424    fn array_holding_rc_items() {
425        struct Item;
426        let _array = [Rc::new(Item)].into_iter().collect::<IArray<Rc<Item>>>();
427    }
428
429    #[test]
430    fn from_iter_is_optimized() {
431        let array_0 = [].into_iter().collect::<IArray<u32>>();
432        assert!(matches!(array_0, IArray::Static(_)));
433        let array_2 = [1, 2].into_iter().collect::<IArray<u32>>();
434        assert!(matches!(array_2, IArray::Rc(_)));
435        {
436            let it = [1].into_iter().filter(|x| x % 2 == 0);
437            assert_eq!(it.size_hint(), (0, Some(1)));
438            let array_0_to_1 = it.collect::<IArray<u32>>();
439            assert!(matches!(array_0_to_1, IArray::Static(_)));
440        }
441        {
442            let it = [2].into_iter().filter(|x| x % 2 == 0);
443            assert_eq!(it.size_hint(), (0, Some(1)));
444            let array_0_to_1 = it.collect::<IArray<u32>>();
445            assert!(matches!(array_0_to_1, IArray::Rc(_)));
446        }
447    }
448
449    #[test]
450    fn static_array() {
451        const _ARRAY: IArray<u32> = IArray::Static(&[1, 2, 3]);
452    }
453
454    #[test]
455    fn deref_slice() {
456        assert!(IArray::Static(&[1, 2, 3]).contains(&1));
457    }
458
459    #[test]
460    fn tuple_in_array() {
461        const _ARRAY_2: IArray<(u32, u32)> = IArray::EMPTY;
462        const _ARRAY_5: IArray<(u32, u32, u32, u32, u32)> = IArray::EMPTY;
463    }
464
465    #[test]
466    fn floats_in_array() {
467        const _ARRAY_F32: IArray<f32> = IArray::EMPTY;
468        const _ARRAY_F64: IArray<f64> = IArray::EMPTY;
469    }
470
471    #[test]
472    fn from() {
473        let x: IArray<u32> = IArray::EMPTY;
474        let _out = IArray::from(&x);
475
476        let _array: IArray<u32> = IArray::from(&[1, 2, 3][..]);
477        let _array: IArray<u32> = IArray::from(vec![1, 2, 3]);
478        let _array: IArray<u32> = IArray::from(Rc::from(vec![1, 2, 3]));
479        let _array: IArray<u32> = IArray::from([1]);
480    }
481
482    #[test]
483    fn recursion() {
484        #[derive(Clone)]
485        struct _Node {
486            _children: IArray<_Node>,
487        }
488
489        impl ImplicitClone for _Node {}
490    }
491
492    #[test]
493    fn into_iter() {
494        let array = IArray::Static(&[1, 2, 3]);
495        assert_eq!(array.iter().next().unwrap(), &1);
496        assert_eq!(array.into_iter().next().unwrap(), 1);
497    }
498}