From 3fe90f641cd3824a65aeb16949d4f919767eb70d Mon Sep 17 00:00:00 2001 From: Niklas Elsbrock Date: Mon, 25 Jul 2022 23:50:08 +0200 Subject: [PATCH] initialize project --- .gitignore | 2 ++ Cargo.toml | 9 ++++++ src/lib.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d7776f1 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "iter_accumulate" +version = "0.1.0" +authors = ["Niklas Elsbrock "] +edition = "2021" +description = "An iterator adaptor that accumulates the elements and yields the current accumulated value for each iteration" +repository = "https://github.com/nelsbrock/iter_accumulate" +license = "Apache-2.0" +keywords = ["accumulate", "iterator", "fold"] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..0623399 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,89 @@ +#![no_std] +#![warn(missing_docs)] + +//! This crate provides the [`accumulate()`](IterAccumulate::accumulate) iterator adaptor. + +/// An iterator adaptor that accumulates the elements from the base iterator using the provided +/// closure. +/// +/// See [`IterAccumulate::accumulate()`] for more information. +pub struct Accumulate { + iter: I, + acc: B, + f: F, +} + +impl Accumulate { + fn new(iter: I, acc: B, f: F) -> Accumulate { + Accumulate { iter, acc, f } + } +} + +impl Iterator for Accumulate +where + I: Iterator, + B: Copy, + F: FnMut(B, I::Item) -> B, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + match self.iter.next() { + Some(item) => { + self.acc = (self.f)(self.acc, item); + Some(self.acc) + } + None => None, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +/// An [`Iterator`] blanket implementation that provides the [`accumulate()`](Self::accumulate) +/// function. +pub trait IterAccumulate: Iterator { + /// Creates an iterator adaptor that accumulates the elements from the base iterator using the + /// provided closure. + /// + /// `accumulate()` is similar to [`fold()`], but instead of returning the final accumulated + /// result, it returns an iterator that yields the current accumulated value for each iteration. + /// In other words, the last element yielded by `accumulate()` is what would have been returned + /// by [`fold()`] if it was used instead. + /// + /// The returned iterator is **not** fused and it is not specified what happens when the base + /// iterator returns [`None`]. + /// If you want a fused iterator, use [`fuse()`]. + /// + /// # Examples + /// + /// ``` + /// use iter_accumulate::IterAccumulate; + /// + /// let input = [1, 2, 3, 4, 5]; + /// let result = input + /// .into_iter() + /// .accumulate(1, |acc, i| acc * i) + /// .collect::>(); + /// + /// assert_eq!(result, vec![1, 2, 6, 24, 120]); + /// ``` + /// + /// [`fold()`]: Iterator::fold + /// [`fuse()`]: Iterator::fuse + #[inline] + fn accumulate(self, init: B, f: F) -> Accumulate + where + Self: Sized, + B: Copy, + F: FnMut(B, Self::Item) -> B, + { + Accumulate::new(self, init, f) + } +} + +impl IterAccumulate for I {}