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