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}