orx_iterable/obj_safe/iterable_obj.rs
1use std::boxed::Box;
2
3/// An `IterableObj` is any type which can return a new boxed iterator that yields
4/// elements of the associated type [`Item`] every time [`boxed_iter`] method is called.
5///
6/// It is the object safe counterpart of [`Iterable`] trait which can conveniently be made into a trait object.
7///
8/// Instead of `iter`, it implements `boxed_iter` which returns the same iterator in a box.
9///
10/// Note that for collections and cloneable iterators, `IterableObj` is implicitly implemented and readily available.
11/// Please refer to [`Iterable`] documentation for details of automatic implementations.
12///
13/// In order to use object safe iterables and collections please add `--features std` and use
14/// `use orx_iterable::{*, obj_safe::*}` to import dependencies rather than `use orx_iterable::*`.
15///
16/// [`Item`]: crate::obj_safe::IterableObj::Item
17/// [`boxed_iter`]: crate::obj_safe::IterableObj::boxed_iter
18/// [`Iterable`]: crate::Iterable
19///
20/// # Examples
21///
22/// ```
23/// use orx_iterable::{*, obj_safe::*};
24/// use arrayvec::ArrayVec;
25/// use smallvec::{smallvec, SmallVec};
26/// use std::collections::{BTreeSet, BinaryHeap, HashSet, LinkedList, VecDeque};
27///
28/// struct Stats {
29/// count: usize,
30/// mean: i64,
31/// std_dev: i64,
32/// }
33///
34/// /// we need multiple iterations over numbers to compute the stats
35/// fn statistics<'a>(numbers: Box<dyn IterableObj<Item = i64> + 'a>) -> Stats {
36/// let count = numbers.boxed_iter().count() as i64;
37/// let sum = numbers.boxed_iter().sum::<i64>();
38/// let mean = sum / count;
39/// let sum_sq_errors: i64 = numbers.boxed_iter().map(|x| (x - mean) * (x - mean)).sum();
40/// let std_dev = f64::sqrt(sum_sq_errors as f64 / (count - 1) as f64) as i64;
41/// Stats {
42/// count: count as usize,
43/// mean,
44/// std_dev,
45/// }
46/// }
47///
48/// // collections as IterableObj
49///
50/// let x = [3, 5, 7];
51/// statistics(Box::new(x.copied()));
52/// // see IterableObj's transformation methods such as copied, mapped, etc.
53///
54/// let x = vec![3, 5, 7];
55/// statistics(Box::new(x.copied()));
56///
57/// let x = LinkedList::from_iter([3, 5, 7]);
58/// statistics(Box::new(x.copied()));
59///
60/// let x = VecDeque::from_iter([3, 5, 7]);
61/// statistics(Box::new(x.copied()));
62///
63/// let x = HashSet::<_>::from_iter([3, 5, 7]);
64/// statistics(Box::new(x.copied()));
65///
66/// let x = BTreeSet::from_iter([3, 5, 7]);
67/// statistics(Box::new(x.copied()));
68///
69/// let x = BinaryHeap::from_iter([3, 5, 7]);
70/// statistics(Box::new(x.copied()));
71///
72/// let x: SmallVec<[_; 128]> = smallvec![3, 5, 7];
73/// statistics(Box::new(x.copied()));
74///
75/// let mut x = ArrayVec::<_, 16>::new();
76/// x.extend([3, 5, 7]);
77/// statistics(Box::new(x.copied()));
78///
79/// // cloneable iterators as IterableObj
80///
81/// let x = Box::new((0..10).map(|x| x * 2).into_iterable());
82/// statistics(x);
83///
84/// let x = vec![1, 2, 3];
85/// let y = Box::new(x
86/// .iter()
87/// .copied()
88/// .filter(|x| x % 2 == 1)
89/// .flat_map(|x| [-x, x])
90/// .into_iterable());
91/// statistics(y);
92///
93/// // lazy generators as IterableObj
94///
95/// statistics(Box::new(7..21i64));
96/// ```
97///
98/// The following example represents an explicit implementation of the Iterable
99/// trait for a lazy generator, which generates a sequence of Fibonacci numbers
100/// up to a set bound.
101///
102/// ```
103/// use orx_iterable::*;
104/// use orx_iterable::obj_safe::*;
105///
106/// struct FibUntilIter {
107/// curr: u32,
108/// next: u32,
109/// until: u32,
110/// }
111///
112/// impl Iterator for FibUntilIter {
113/// type Item = u32;
114///
115/// fn next(&mut self) -> Option<Self::Item> {
116/// let current = self.curr;
117/// self.curr = self.next;
118/// self.next = current + self.next;
119/// match current > self.until {
120/// false => Some(current),
121/// true => None,
122/// }
123/// }
124/// }
125///
126/// struct FibUntil(u32);
127///
128/// impl IterableObj for FibUntil {
129/// type Item = u32;
130///
131/// fn boxed_iter(&self) -> Box<dyn Iterator<Item = Self::Item> + '_> {
132/// Box::new(FibUntilIter { curr: 0, next: 1, until: self.0 })
133/// }
134/// }
135///
136/// let fib = FibUntil(10); // IterableObj
137///
138/// assert_eq!(fib.boxed_iter().count(), 7);
139/// assert_eq!(fib.boxed_iter().max(), Some(8));
140/// assert_eq!(fib.boxed_iter().collect::<Vec<_>>(), [0, 1, 1, 2, 3, 5, 8]);
141/// ```
142pub trait IterableObj {
143 /// Type of the item that the iterators created by the [`boxed_iter`] method yields.
144 ///
145 /// [`boxed_iter`]: crate::obj_safe::IterableObj::boxed_iter
146 type Item;
147
148 /// Creates a new iterator in a box from this iterable yielding elements of type `IterableObj::Item`.
149 fn boxed_iter(&self) -> Box<dyn Iterator<Item = Self::Item> + '_>;
150}
151
152// impl
153
154impl<'a, X> IterableObj for &'a X
155where
156 &'a X: IntoIterator,
157{
158 type Item = <&'a X as IntoIterator>::Item;
159
160 fn boxed_iter(&self) -> Box<dyn Iterator<Item = Self::Item> + '_> {
161 Box::new(self.into_iter())
162 }
163}
164
165impl<'a, X> IterableObj for &'a [X] {
166 type Item = &'a X;
167
168 fn boxed_iter(&self) -> Box<dyn Iterator<Item = Self::Item> + '_> {
169 Box::new(<[X]>::iter(self))
170 }
171}