aboutsummaryrefslogtreecommitdiff
path: root/beer-song/src/intersperse.rs
diff options
context:
space:
mode:
authorFederico I <git@federicoigne.com>2020-03-17 00:53:30 +0000
committerFederico Igne <git@federicoigne.com>2021-11-03 18:54:45 +0000
commitac194ed95d6b97eef6dd60f8a3524f63fa408553 (patch)
treea7e5ae82dc02475ff711cd5e39ae1e4817276624 /beer-song/src/intersperse.rs
parenta4b6e4b2e898b7efa0b44b490bd731557b0cc41b (diff)
downloadexercism-ac194ed95d6b97eef6dd60f8a3524f63fa408553.tar.gz
exercism-ac194ed95d6b97eef6dd60f8a3524f63fa408553.zip
[rust] Beer Song
Diffstat (limited to 'beer-song/src/intersperse.rs')
-rw-r--r--beer-song/src/intersperse.rs52
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 @@
1use 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.
7pub 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
14impl<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
25impl<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.
43pub 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
52impl<I: Iterator> IntersperseIterator for I {}