From 02481656966b0a8dfc95cf3c22bcc049660ff7d4 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Sat, 26 Dec 2020 17:48:38 +0000 Subject: Move Rust exercises in a subdirectory --- rust/beer-song/src/intersperse.rs | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 rust/beer-song/src/intersperse.rs (limited to 'rust/beer-song/src/intersperse.rs') diff --git a/rust/beer-song/src/intersperse.rs b/rust/beer-song/src/intersperse.rs new file mode 100644 index 0000000..51580e6 --- /dev/null +++ b/rust/beer-song/src/intersperse.rs @@ -0,0 +1,52 @@ +use std::rc::Rc; + +/// An iterator that allows to insert a given element `elem` every `interval` elements of the input +/// iterator. +/// +/// The interleaved element is wrapped in a `Rc` smart pointer to avoid hard copies. +pub struct Intersperse { + inner: std::iter::Peekable, // required to have `peek(..)` + elem: Rc, + interval: u32, + intersperse: u32, +} + +impl Intersperse { + pub fn new(inner: I, elem: I::Item, interval: u32) -> Intersperse { + Intersperse { + inner: inner.peekable(), + elem: Rc::new(elem), + interval: interval + 1, // `+ 1` needed to align semantics and implementation + intersperse: 0, + } + } +} + +impl Iterator for Intersperse { + type Item = Rc; + + fn next(&mut self) -> Option { + // Counter rotation + self.intersperse = (self.intersperse + 1) % self.interval; + // Insert a copy of the element only when counter goes to 0 and we haven't reached the end + // of the inner iterator. + if self.intersperse == 0 && self.inner.peek().is_some() { + Some(Rc::clone(&self.elem)) + } else { + self.inner.next() + .map(|x| Rc::new(x)) // Go from Option to Option> + } + } +} + +/// Extend `Iterator`s with `intersperse` function. +pub trait IntersperseIterator: Iterator { + fn intersperse(self, elem: Self::Item, interval: u32) -> Intersperse + where + Self: Sized, + { + Intersperse::new(self, elem, interval) + } +} + +impl IntersperseIterator for I {} -- cgit v1.2.3