orx_iterable/
collection.rs

1use crate::{
2    transformations::{
3        ChainedCol, FilteredCol, FlattenedCol, FusedCol, ReversedCol, SkippedCol, SkippedWhileCol,
4        SteppedByCol, TakenCol, TakenWhileCol,
5    },
6    Iterable,
7};
8
9/// A collection providing the `iter` method which returns an iterator over shared references
10/// of elements of the collection.
11///
12/// # Auto Implementations
13///
14/// Consider a collection type `X` storing elements of type `T`. Provided that the following implementations are provided:
15///
16/// * `X: IntoIterator<Item = T>`
17/// * `&X: IntoIterator<Item = &T>`
18///
19/// Then, `X` implements `Collection<Item = T>`.
20/// Further, `&X` implements `Iterable<Item = &T>`.
21///
22/// # Examples
23///
24/// ```
25/// use orx_iterable::*;
26/// use arrayvec::ArrayVec;
27/// use smallvec::{smallvec, SmallVec};
28/// use std::collections::{BinaryHeap, BTreeSet, HashSet, LinkedList, VecDeque};
29///
30/// struct Stats {
31///     count: usize,
32///     mean: i64,
33///     std_dev: i64,
34/// }
35///
36/// /// we need multiple iterations over numbers to compute the stats
37/// fn statistics(numbers: &impl Collection<Item = i64>) -> Stats {
38///     let count = numbers.iter().count() as i64;
39///     let sum = numbers.iter().sum::<i64>();
40///     let mean = sum / count;
41///     let sum_sq_errors: i64 = numbers.iter().map(|x| (x - mean) * (x - mean)).sum();
42///     let std_dev = f64::sqrt(sum_sq_errors as f64 / (count - 1) as f64) as i64;
43///     Stats {
44///         count: count as usize,
45///         mean,
46///         std_dev,
47///     }
48/// }
49///
50/// // example collections that automatically implement Collection
51///
52/// statistics(&[3, 5, 7]);
53/// statistics(&vec![3, 5, 7]);
54/// statistics(&LinkedList::from_iter([3, 5, 7]));
55/// statistics(&VecDeque::from_iter([3, 5, 7]));
56/// statistics(&HashSet::<_>::from_iter([3, 5, 7]));
57/// statistics(&BTreeSet::<_>::from_iter([3, 5, 7]));
58/// statistics(&BinaryHeap::<_>::from_iter([3, 5, 7]));
59///
60/// let x: SmallVec<[_; 128]> = smallvec![3, 5, 7];
61/// statistics(&x);
62///
63/// let mut x = ArrayVec::<_, 16>::new();
64/// x.extend([3, 5, 7]);
65/// statistics(&x);
66/// ```
67pub trait Collection {
68    /// Type of elements stored by the collection.
69    type Item;
70
71    /// Related type implementing `Iterable` trait that the `as_iterable` method returns.
72    /// If the type of the `Collection` is `X`, the corresponding `Iterable` type is almost
73    /// always `&X` due to the following relation among the both traits.
74    ///
75    /// Practically, these definitions correspond to the following relations:
76    /// * if a collection `X` implements [`Collection<Item = T>`], then `&X` implements [`Iterable<Item = &T>`];
77    /// * on the other hand, a type implementing [`Iterable`] may not be a collection at all, such as [`Range<usize>`],
78    ///   and hence, does not necessarily implement [`Collection`].
79    ///
80    /// [`Range<usize>`]: core::ops::Range
81    type Iterable<'i>: Iterable<Item = &'i Self::Item>
82    where
83        Self: 'i;
84
85    /// Creates a new iterator yielding references to the elements of the collection; i.e.,
86    /// type of elements is `&Collection::Item`.
87    fn iter(&self) -> <Self::Iterable<'_> as Iterable>::Iter {
88        self.as_iterable().iter()
89    }
90
91    /// Returns the corresponding `Iterable` type of this collection, which is often nothing but `&Self`.
92    fn as_iterable(&self) -> Self::Iterable<'_>;
93
94    // provided
95
96    /// Consumes this collection and `other`; creates an iterable collection which is a chain of these two
97    /// collections.
98    ///
99    /// Note that this method does not change the memory locations of the elements; i.e.,
100    /// the elements still live in two separate collections; however, now chained together.
101    ///
102    /// # Examples
103    ///
104    /// ```
105    /// use orx_iterable::*;
106    ///
107    /// let a = vec!['a', 'b'];
108    /// let b = ['c', 'd', 'e'];
109    ///
110    /// let mut it = a.into_chained(b);
111    ///
112    /// *it.iter_mut().last().unwrap() = 'x';
113    ///
114    /// assert_eq!(it.iter().count(), 5);
115    /// assert_eq!(it.iter().collect::<Vec<_>>(), vec![&'a', &'b', &'c', &'d', &'x']);
116    /// ```
117    fn into_chained<I>(self, other: I) -> ChainedCol<Self, I, Self, I>
118    where
119        Self: Sized,
120        I: Collection<Item = Self::Item>,
121    {
122        ChainedCol {
123            it1: self,
124            it2: other,
125            phantom: Default::default(),
126        }
127    }
128
129    /// Consumes this collection and creates an iterable collection which is a filtered version of this collection.
130    ///
131    /// # Examples
132    ///
133    /// ```
134    /// use orx_iterable::*;
135    ///
136    /// let a = [0i32, 1, 2];
137    ///
138    /// let mut it = a.into_filtered(|x| x.is_positive());
139    ///
140    /// for x in it.iter_mut() {
141    ///     *x *= 2;
142    /// }
143    ///
144    /// assert_eq!(it.iter().count(), 2);
145    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&2, &4]);
146    /// ```
147    fn into_filtered<P>(self, filter: P) -> FilteredCol<Self, Self, P>
148    where
149        Self: Sized,
150        P: Fn(&Self::Item) -> bool + Copy,
151    {
152        FilteredCol {
153            it: self,
154            filter,
155            phantom: Default::default(),
156        }
157    }
158
159    /// Consumes this collection and creates an iterable collection which is a flattened version of this collection.
160    ///
161    /// # Examples
162    ///
163    /// ```
164    /// use orx_iterable::*;
165    ///
166    /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]];
167    ///
168    /// let mut it = data.into_flattened();
169    ///
170    /// for x in it.iter_mut() {
171    ///     *x *= 2;
172    /// }
173    ///
174    /// assert_eq!(it.iter().count(), 6);
175    /// assert_eq!(it.iter().sum::<u32>(), 2 * 21);
176    /// ```
177    fn into_flattened(self) -> FlattenedCol<Self, Self>
178    where
179        Self: Sized,
180        Self::Item: IntoIterator,
181        for<'i> &'i Self::Item: IntoIterator<Item = &'i <Self::Item as IntoIterator>::Item>,
182    {
183        FlattenedCol {
184            it: self,
185            phantom: Default::default(),
186        }
187    }
188
189    /// Consumes this collection and creates an iterable collection which is a fused version of this collection.
190    ///
191    /// See [`core::iter::Fuse`] for details on fused iterators.
192    fn into_fused(self) -> FusedCol<Self, Self>
193    where
194        Self: Sized,
195    {
196        FusedCol {
197            it: self,
198            phantom: Default::default(),
199        }
200    }
201
202    /// Consumes this collection and creates an iterable collection which is a reversed version of this collection.
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// use orx_iterable::*;
208    ///
209    /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]];
210    ///
211    /// let a = [1, 2, 3];
212    ///
213    /// let it = a.into_reversed();
214    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&3, &2, &1]);
215    ///
216    /// let it = it.into_reversed();
217    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&1, &2, &3]);
218    /// ```
219    fn into_reversed(self) -> ReversedCol<Self, Self>
220    where
221        Self: Sized,
222        for<'b> <Self::Iterable<'b> as Iterable>::Iter: DoubleEndedIterator,
223    {
224        ReversedCol {
225            it: self,
226            phantom: Default::default(),
227        }
228    }
229
230    /// Consumes this collection and creates an iterable collection which is skipped-by-`n` version of this collection.
231    ///
232    /// # Examples
233    ///
234    /// ```
235    /// use orx_iterable::*;
236    ///
237    /// let a = [1, 2, 3, 4, 5];
238    ///
239    /// let it = a.into_skipped(2);
240    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&3, &4, &5]);
241    ///
242    /// let it = it.into_skipped(1);
243    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&4, &5]);
244    /// ```
245    fn into_skipped(self, n: usize) -> SkippedCol<Self, Self>
246    where
247        Self: Sized,
248    {
249        SkippedCol {
250            it: self,
251            n,
252            phantom: Default::default(),
253        }
254    }
255
256    /// Consumes this collection and creates an iterable collection which is skipped-while version of this collection.
257    ///
258    /// # Examples
259    ///
260    /// ```
261    /// use orx_iterable::*;
262    ///
263    /// let a = [-1i32, 0, 1];
264    ///
265    /// let it = a.into_skipped_while(|x| x.is_negative());
266    ///
267    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&0, &1]);
268    /// ```
269    fn into_skipped_while<P>(self, skip_while: P) -> SkippedWhileCol<Self, Self, P>
270    where
271        Self: Sized,
272        P: Fn(&Self::Item) -> bool + Copy,
273    {
274        SkippedWhileCol {
275            it: self,
276            skip_while,
277            phantom: Default::default(),
278        }
279    }
280
281    /// Consumes this collection and creates an iterable collection which is stepped-by-`step` version of this collection.
282    ///
283    /// # Examples
284    ///
285    /// ```
286    /// use orx_iterable::*;
287    ///
288    /// let a = [0, 1, 2, 3, 4, 5];
289    ///
290    /// let it = a.into_stepped_by(2);
291    ///
292    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&0, &2, &4]);
293    /// ```
294    fn into_stepped_by(self, step: usize) -> SteppedByCol<Self, Self>
295    where
296        Self: Sized,
297    {
298        SteppedByCol {
299            it: self,
300            step,
301            phantom: Default::default(),
302        }
303    }
304
305    /// Consumes this collection and creates an iterable collection which is taken-`n` version of this collection.
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use orx_iterable::*;
311    ///
312    /// let a = [1, 2, 3, 4, 5];
313    ///
314    /// let it = a.into_taken(3);
315    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&1, &2, &3]);
316    ///
317    /// let it = it.into_taken(2);
318    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&1, &2]);
319    /// ```
320    fn into_taken(self, n: usize) -> TakenCol<Self, Self>
321    where
322        Self: Sized,
323    {
324        TakenCol {
325            it: self,
326            n,
327            phantom: Default::default(),
328        }
329    }
330
331    /// Consumes this collection and creates an iterable collection which is taken-while version of this collection.
332    ///
333    /// # Examples
334    ///
335    /// ```
336    /// use orx_iterable::*;
337    ///
338    /// let a = [-1i32, 0, 1];
339    ///
340    /// let it = a.into_taken_while(|x| x.is_negative());
341    ///
342    /// assert_eq!(it.iter().collect::<Vec<_>>(), [&-1]);
343    /// ```
344    fn into_taken_while<P>(self, take_while: P) -> TakenWhileCol<Self, Self, P>
345    where
346        Self: Sized,
347        P: Fn(&Self::Item) -> bool + Copy,
348    {
349        TakenWhileCol {
350            it: self,
351            take_while,
352            phantom: Default::default(),
353        }
354    }
355}
356
357impl<X> Collection for X
358where
359    X: IntoIterator,
360    for<'a> &'a X: IntoIterator<Item = &'a <X as IntoIterator>::Item>,
361{
362    type Item = <X as IntoIterator>::Item;
363
364    type Iterable<'i>
365        = &'i X
366    where
367        Self: 'i;
368
369    fn iter(&self) -> <Self::Iterable<'_> as Iterable>::Iter {
370        <&X as IntoIterator>::into_iter(self)
371    }
372
373    fn as_iterable(&self) -> Self::Iterable<'_> {
374        self
375    }
376}