1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! A base library for interfacing with streams of vectors and matrices.
//!
//! This library presents the abstraction layer for the _streaming model_.
//! Essentially, it provides a set of handy utilities as a wrapper around
//! iterators.

mod rev;
pub use rev::Reverse;

/// The trait [`Iterable`] represents a streamable object that can produce
/// an arbitrary number of streams of length [`Iterable::len`](Iterable::len).
///
/// An Iterable is pretty much like an [`IntoIterator`] that can be copied over
/// and over, and has an hint of the length.  Copies are meant to be shared
/// across threads safely.
///
/// # Examples
///
/// ```
/// use ark_std::borrow::Borrow;
/// use ark_std::iterable::Iterable;
///
/// // Relying only on standard library
/// fn f(xs: impl IntoIterator<Item=impl Borrow<u32>> + Clone) -> u32 {
///     xs.clone().into_iter().fold(1, |x, y| x.borrow() * y.borrow()) +
///     xs.clone().into_iter().fold(0, |x, y| x.borrow() + y.borrow()) +
///     xs.into_iter().size_hint().0 as u32
/// }
///
/// // Relying on the trait below
/// fn g(xs: impl Iterable<Item=impl Borrow<u32>>) -> u32 {
///     xs.iter().fold(1, |x, y| x.borrow() * y.borrow()) +
///     xs.iter().fold(0, |x, y| x.borrow() + y.borrow()) +
///     xs.len() as u32
/// }
///
/// // Test over a slice (which implements both traits).
/// let xs = &[1, 2, 3, 4];
/// assert_eq!(f(xs), g(xs));
/// ```
///
/// # Efficency
///
/// For efficiency, functions using iterables are often times relying on
/// [`Borrow`](std::borrow::Borrow) in order to avoid copying the contents of
/// the iterator..
///
/// The `Iter` associated type has a lifetime that is independent from that of
/// the [`Iterable`] object. This means that implicitly a copy of the relevant
/// contents of the object will happen whenever
/// [`Iterable::iter`](crate::iterable::Iterable::iter) is called. This might
/// change in the future as associated type constructors
/// [[RFC1598](https://github.com/rust-lang/rfcs/blob/master/text/1598-generic_associated_types.md#declaring--assigning-an-associated-type-constructor)]
/// stabilize.
///
/// # Future implementation
///
/// A lot of stream operations must be performed symbolically.
/// We expect that, in the future, this trait will accommodate for additional
/// streaming function, e.g. `Iterable::hadamard(&self, other: &Iterable)` to
/// perform the Hadamard product of two streams, or `Iterable::add(&self, other:
/// &Iterable)` to perform the addition of two streams.
pub trait Iterable: Send + Sync {
    /// The type of the element being streamed.
    type Item;
    /// The type of the iterator being generated.
    type Iter: Iterator<Item = Self::Item>;

    ///  Return the iterator associated to the current instance.
    ///
    /// In the so-called _streaming model_ [BCHO22], this is equivalent to
    /// instantiating a new stream tape.
    /// For base types, this acts in the same way as the `.iter()` method.
    ///
    ///  ```
    /// use ark_std::iterable::Iterable;
    ///
    /// let x = &[1, 2, 4];
    /// let mut iterator = x.iter();
    ///  ```
    fn iter(&self) -> Self::Iter;

    /// Return a hint on the length of the stream.
    ///
    /// Careful: different objects might have different indications of what
    /// _length_ means; this might not be the actual size in terms of
    /// elements.
    fn len(&self) -> usize;

    /// Return `true` if the stream is empty, else `false`.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl<I> Iterable for I
where
    I: IntoIterator + Copy + Send + Sync,
    I::IntoIter: ExactSizeIterator,
{
    type Item = <I as IntoIterator>::Item;
    type Iter = <I as IntoIterator>::IntoIter;

    fn iter(&self) -> Self::Iter {
        self.into_iter()
    }

    fn len(&self) -> usize {
        self.into_iter().len()
    }
}