diff options
| author | Federico I <git@federicoigne.com> | 2020-03-17 00:53:30 +0000 |
|---|---|---|
| committer | Federico Igne <git@federicoigne.com> | 2021-11-03 18:54:45 +0000 |
| commit | ac194ed95d6b97eef6dd60f8a3524f63fa408553 (patch) | |
| tree | a7e5ae82dc02475ff711cd5e39ae1e4817276624 /beer-song/src/intersperse.rs | |
| parent | a4b6e4b2e898b7efa0b44b490bd731557b0cc41b (diff) | |
| download | exercism-ac194ed95d6b97eef6dd60f8a3524f63fa408553.tar.gz exercism-ac194ed95d6b97eef6dd60f8a3524f63fa408553.zip | |
[rust] Beer Song
Diffstat (limited to 'beer-song/src/intersperse.rs')
| -rw-r--r-- | beer-song/src/intersperse.rs | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/beer-song/src/intersperse.rs b/beer-song/src/intersperse.rs new file mode 100644 index 0000000..51580e6 --- /dev/null +++ b/beer-song/src/intersperse.rs | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | use std::rc::Rc; | ||
| 2 | |||
| 3 | /// An iterator that allows to insert a given element `elem` every `interval` elements of the input | ||
| 4 | /// iterator. | ||
| 5 | /// | ||
| 6 | /// The interleaved element is wrapped in a `Rc` smart pointer to avoid hard copies. | ||
| 7 | pub struct Intersperse<I: Iterator> { | ||
| 8 | inner: std::iter::Peekable<I>, // required to have `peek(..)` | ||
| 9 | elem: Rc<I::Item>, | ||
| 10 | interval: u32, | ||
| 11 | intersperse: u32, | ||
| 12 | } | ||
| 13 | |||
| 14 | impl<I: Iterator> Intersperse<I> { | ||
| 15 | pub fn new(inner: I, elem: I::Item, interval: u32) -> Intersperse<I> { | ||
| 16 | Intersperse { | ||
| 17 | inner: inner.peekable(), | ||
| 18 | elem: Rc::new(elem), | ||
| 19 | interval: interval + 1, // `+ 1` needed to align semantics and implementation | ||
| 20 | intersperse: 0, | ||
| 21 | } | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | impl<I: Iterator> Iterator for Intersperse<I> { | ||
| 26 | type Item = Rc<I::Item>; | ||
| 27 | |||
| 28 | fn next(&mut self) -> Option<Self::Item> { | ||
| 29 | // Counter rotation | ||
| 30 | self.intersperse = (self.intersperse + 1) % self.interval; | ||
| 31 | // Insert a copy of the element only when counter goes to 0 and we haven't reached the end | ||
| 32 | // of the inner iterator. | ||
| 33 | if self.intersperse == 0 && self.inner.peek().is_some() { | ||
| 34 | Some(Rc::clone(&self.elem)) | ||
| 35 | } else { | ||
| 36 | self.inner.next() | ||
| 37 | .map(|x| Rc::new(x)) // Go from Option<I::Item> to Option<Rc<I::Item>> | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | /// Extend `Iterator`s with `intersperse` function. | ||
| 43 | pub trait IntersperseIterator: Iterator { | ||
| 44 | fn intersperse(self, elem: Self::Item, interval: u32) -> Intersperse<Self> | ||
| 45 | where | ||
| 46 | Self: Sized, | ||
| 47 | { | ||
| 48 | Intersperse::new(self, elem, interval) | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | impl<I: Iterator> IntersperseIterator for I {} | ||
