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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! An iterator over data wrapped in `Cow`.
//!
//! See the documentation for [`CowIter`] for more.
//!
//! [`CowIter`]: enum.CowIter.html

use std::borrow::Cow;
use std::marker::PhantomData;

/// An iterator over data wrapped in `Cow`.
///
/// This allows to create iterators from data wrapped in `Cow` easily. The
/// value returned at each iteration will be either `Owned` or `Borrowed`,
/// depending on the initial object variant.
///
/// # Example
///
/// In this example, we use the borrowed variant:
///
/// ```
/// use std::borrow::Cow;
/// use butcher::iterator::CowIter;
///
/// // Notice that the generic type is annotated
/// let data: Cow<[_]> = Cow::Owned(vec![0, 1, 1, 3]);
/// let mut input = CowIter::from_cow(data);
///
/// assert_eq!(input.next(), Some(Cow::Owned(0)));
/// assert_eq!(input.next(), Some(Cow::Owned(1)));
/// assert_eq!(input.next(), Some(Cow::Owned(1)));
/// assert_eq!(input.next(), Some(Cow::Owned(3)));
/// assert_eq!(input.next(), None)
/// ```
///
/// Here, we use the owned variant:
///
/// ```
/// use std::borrow::Cow;
/// use butcher::iterator::CowIter;
///
/// let data = Cow::Borrowed(&[0, 1, 1, 3] as &[_]);
/// let mut input = CowIter::from_cow(data);
///
/// assert_eq!(input.next(), Some(Cow::Borrowed(&0)));
/// assert_eq!(input.next(), Some(Cow::Borrowed(&1)));
/// assert_eq!(input.next(), Some(Cow::Borrowed(&1)));
/// assert_eq!(input.next(), Some(Cow::Borrowed(&3)));
/// assert_eq!(input.next(), None)
/// ```
///
/// # Generics
///
/// This enum uses a lot of generics in order to work. Users should not care
/// about them. Most of the use cases may not require to manually specify the
/// generic types.
///
/// The only annotation which *may* be required is `Input` when
/// explicitely dealing with the `Owned` variant. Fortunately, this can be
/// circumvented by specifying the generic type of the associated `Cow`
/// somewhere. This can be specified when the `Cow` is created, or in the
/// function signature.
pub enum CowIter<'a, I, Input, Iterr1, Iterr2>
where
    I: 'a + ToOwned,
    Iterr1: Iterator<Item = &'a I>,
    Iterr2: Iterator<Item = <I as ToOwned>::Owned>,
    Input: 'a + ToOwned + ?Sized,
    &'a Input: IntoIterator<Item = &'a I, IntoIter = Iterr1> + ToOwned,
    <Input as ToOwned>::Owned: IntoIterator<Item = <I as ToOwned>::Owned, IntoIter = Iterr2>,
{
    Borrowed(Iterr1, PhantomData<Input>),
    Owned(Iterr2, PhantomData<Input>),
}

impl<'a, I, Input, Iterr1, Iterr2> CowIter<'a, I, Input, Iterr1, Iterr2>
where
    I: 'a + ToOwned,
    Iterr1: Iterator<Item = &'a I>,
    Iterr2: Iterator<Item = <I as ToOwned>::Owned>,
    Input: 'a + ToOwned + ?Sized,
    &'a Input: IntoIterator<Item = &'a I, IntoIter = Iterr1>,
    <Input as ToOwned>::Owned: IntoIterator<Item = <I as ToOwned>::Owned, IntoIter = Iterr2>,
{
    /// Creates a `CowIter` from a `Cow` containing an owned or borrowed object
    /// which can be iterated over.
    // TODO: write a test for this function
    pub fn from_cow(i: Cow<'a, Input>) -> CowIter<I, Input, Iterr1, Iterr2> {
        match i {
            Cow::Owned(i) => CowIter::Owned(i.into_iter(), PhantomData),
            Cow::Borrowed(i) => {
                let i: &'a Input = i;
                CowIter::Borrowed(i.into_iter(), PhantomData)
            }
        }
    }
}

impl<'a, Input, I, Iterr1, Iterr2> From<Cow<'a, Input>> for CowIter<'a, I, Input, Iterr1, Iterr2>
where
    I: 'a + ToOwned,
    Iterr1: Iterator<Item = &'a I>,
    Iterr2: Iterator<Item = <I as ToOwned>::Owned>,
    Input: 'a + ToOwned + ?Sized,
    &'a Input: IntoIterator<Item = &'a I, IntoIter = Iterr1> + ToOwned,
    <Input as ToOwned>::Owned: IntoIterator<Item = <I as ToOwned>::Owned, IntoIter = Iterr2>,
{
    // TODO: write a test for this function
    fn from(input: Cow<'a, Input>) -> Self {
        CowIter::from_cow(input)
    }
}

impl<'a, I, Input, Iterr1, Iterr2> Iterator for CowIter<'a, I, Input, Iterr1, Iterr2>
where
    I: 'a + ToOwned,
    Iterr1: Iterator<Item = &'a I>,
    Iterr2: Iterator<Item = <I as ToOwned>::Owned>,
    Input: 'a + ToOwned + ?Sized,
    &'a Input: IntoIterator<Item = &'a I, IntoIter = Iterr1> + ToOwned,
    <Input as ToOwned>::Owned: IntoIterator<Item = <I as ToOwned>::Owned, IntoIter = Iterr2>,
{
    type Item = Cow<'a, I>;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            CowIter::Borrowed(it, _) => it.next().map(Cow::Borrowed),
            CowIter::Owned(it, _) => it.next().map(Cow::Owned),
        }
    }
}

/// Allows to convert any cow containing an iterator into a `CowIter`.
///
/// This trait provides better method-chaining, but is just a simple wrapper
/// for [`CowIter::from_cow`].
///
/// [`CowIter::from_cow`]: enum.CowIter.html#method.from_cow
pub trait IntoCowIterator {
    type Item: ToOwned;
    type IntoIter: Iterator;

    fn into_cow_iter(self) -> Self::IntoIter;
}

impl<'a, Input, I, Iterr1, Iterr2> IntoCowIterator for Cow<'a, Input>
where
    I: 'a + ToOwned,
    Iterr1: Iterator<Item = &'a I>,
    Iterr2: Iterator<Item = <I as ToOwned>::Owned>,
    Input: 'a + ToOwned + ?Sized,
    &'a Input: IntoIterator<Item = &'a I, IntoIter = Iterr1> + ToOwned,
    <Input as ToOwned>::Owned: IntoIterator<Item = <I as ToOwned>::Owned, IntoIter = Iterr2>,
{
    type Item = I;
    type IntoIter = CowIter<'a, I, Input, Iterr1, Iterr2>;

    // TODO: write a test for this function
    fn into_cow_iter(self) -> Self::IntoIter {
        CowIter::from_cow(self)
    }
}



#[cfg(test)]
mod cow_iter {
    use super::*;

    #[test]
    fn iterator_owned() {
        let numbers: Cow<[_]> = Cow::Owned(vec![0, 1, 1, 2, 3, 5]);
        let mut iter = CowIter::from_cow(numbers);

        assert_eq!(iter.next(), Some(Cow::Owned(0)));
        assert_eq!(iter.next(), Some(Cow::Owned(1)));
        assert_eq!(iter.next(), Some(Cow::Owned(1)));
        assert_eq!(iter.next(), Some(Cow::Owned(2)));
        assert_eq!(iter.next(), Some(Cow::Owned(3)));
        assert_eq!(iter.next(), Some(Cow::Owned(5)));
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn iterator_borrowed() {
        let numbers: Cow<[_]> = Cow::Borrowed(&[0, 1, 1, 2, 3, 5] as &[_]);
        let mut iter = CowIter::from_cow(numbers);

        assert_eq!(iter.next(), Some(Cow::Borrowed(&0)));
        assert_eq!(iter.next(), Some(Cow::Borrowed(&1)));
        assert_eq!(iter.next(), Some(Cow::Borrowed(&1)));
        assert_eq!(iter.next(), Some(Cow::Borrowed(&2)));
        assert_eq!(iter.next(), Some(Cow::Borrowed(&3)));
        assert_eq!(iter.next(), Some(Cow::Borrowed(&5)));
        assert_eq!(iter.next(), None);
    }
}