From 03ad448fc30ba501958ae7667692c91b3a3f8bdd Mon Sep 17 00:00:00 2001 From: asonix Date: Sun, 26 Jul 2020 10:14:52 -0500 Subject: [PATCH] Make OneOrMany iterable --- Cargo.toml | 2 +- README.md | 2 +- examples/de.rs | 2 +- src/lib.rs | 4 +- src/primitives/one_or_many.rs | 310 ++++++++++++++++++++++++++++++++++ 5 files changed, 315 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 065d5b6..af7b27e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "activitystreams" description = "A set of core types and traits for activitystreams data" -version = "0.7.0-alpha.1" +version = "0.7.0-alpha.2" license = "GPL-3.0" authors = ["asonix "] repository = "https://git.asonix.dog/Aardwolf/activitystreams" diff --git a/README.md b/README.md index 75f887f..8e231db 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ _A set of Traits and Types that make up the ActivityStreams and ActivityPub spec First, add ActivityStreams to your dependencies ```toml [dependencies] -activitystreams = "0.7.0-alpha.0" +activitystreams = "0.7.0-alpha.2" ``` ### Types diff --git a/examples/de.rs b/examples/de.rs index f03746e..3dc5dc4 100644 --- a/examples/de.rs +++ b/examples/de.rs @@ -49,7 +49,7 @@ fn main() -> Result<(), Error> { let v: Vec> = collection .take_items() .into_iter() - .map(|o| o.many().into_iter().flatten()) + .map(|o| o.into_iter()) .flatten() .filter_map(|any_base| any_base.take_base()) .map(|base| base.solidify().and_then(|o| o.extend())) diff --git a/src/lib.rs b/src/lib.rs index dd95219..f050c97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ //! First, add ActivityStreams to your dependencies //! ```toml //! [dependencies] -//! activitystreams = "0.7.0-alpha.0" +//! activitystreams = "0.7.0-alpha.2" //! ``` //! //! ### Types @@ -293,7 +293,7 @@ //! //! You should have received a copy of the GNU General Public License along with ActivityStreams. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). -#![doc(html_root_url = "https://docs.rs/activitystreams/0.7.0-alpha.1/activitystreams")] +#![doc(html_root_url = "https://docs.rs/activitystreams/0.7.0-alpha.2/activitystreams")] pub mod activity; pub mod actor; diff --git a/src/primitives/one_or_many.rs b/src/primitives/one_or_many.rs index a9eb1ff..cad93f2 100644 --- a/src/primitives/one_or_many.rs +++ b/src/primitives/one_or_many.rs @@ -22,7 +22,70 @@ use crate::either::Either; #[serde(transparent)] pub struct OneOrMany(pub(crate) Either>); +/// An iterator over a OneOrMany's borrowed contents +#[derive(Clone, Debug)] +pub struct Iter<'a, T>(Either, std::slice::Iter<'a, T>>); + +/// An iterator over a OneOrMany's mutably borrowed contents +#[derive(Debug)] +pub struct IterMut<'a, T>(Either, std::slice::IterMut<'a, T>>); + +/// An iterator consuming a OneOrMany +#[derive(Clone, Debug)] +pub struct IntoIter(Either, std::vec::IntoIter>); + impl OneOrMany { + /// Construct an iterator over borrows of the OneOrMany's contents + /// + /// ```rust + /// use activitystreams::primitives::OneOrMany; + /// + /// let value = OneOrMany::from_one(String::from("hi")); + /// + /// for item in value.iter() { + /// println!("{}", item); + /// } + /// ``` + pub fn iter<'a>(&'a self) -> Iter<'a, T> { + match self.0 { + Either::Left(ref t) => Iter(Either::Left(Some(t))), + Either::Right(ref v) => Iter(Either::Right(v.iter())), + } + } + + /// Construct an iterator over mutable borrows of the OneOrMany's contents + /// + /// ```rust + /// use activitystreams::primitives::OneOrMany; + /// + /// let mut value = OneOrMany::from_one(String::from("hi")); + /// + /// for item in value.iter_mut() { + /// item.push_str("hey"); + /// } + /// ``` + pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { + match self.0 { + Either::Left(ref mut t) => IterMut(Either::Left(Some(t))), + Either::Right(ref mut v) => IterMut(Either::Right(v.iter_mut())), + } + } + + /// Construct an iterator over the OneOrMany's contents, consuming the OneOrMany + /// + /// ```rust + /// use activitystreams::primitives::OneOrMany; + /// + /// let value = OneOrMany::from_one(String::from("hi")); + /// let vec = value.into_iter().map(|s| s + "hello").collect::>(); + /// ``` + pub fn into_iter(self) -> IntoIter { + match self.0 { + Either::Left(t) => IntoIter(Either::Left(Some(t))), + Either::Right(v) => IntoIter(Either::Right(v.into_iter())), + } + } + /// Create a OneOrMany referencing the existing one /// /// ```rust @@ -279,6 +342,213 @@ impl OneOrMany { } } +impl IntoIterator for OneOrMany { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + OneOrMany::into_iter(self) + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + match self.0 { + Either::Left(ref mut opt) => opt.take(), + Either::Right(ref mut iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self.0 { + Either::Left(ref opt) if opt.is_some() => (1, Some(1)), + Either::Left(_) => (0, Some(0)), + Either::Right(ref iter) => iter.size_hint(), + } + } + + fn count(self) -> usize { + match self.0 { + Either::Left(opt) => { + if opt.is_some() { + 1 + } else { + 0 + } + } + Either::Right(iter) => iter.count(), + } + } + + fn last(self) -> Option { + match self.0 { + Either::Left(mut opt) => opt.take(), + Either::Right(iter) => iter.last(), + } + } + + fn nth(&mut self, n: usize) -> Option { + match self.0 { + Either::Left(ref mut opt) if n == 0 => opt.take(), + Either::Left(_) => None, + Either::Right(ref mut iter) => iter.nth(n), + } + } +} + +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + fn next_back(&mut self) -> Option { + match self.0 { + Either::Left(ref mut opt) => opt.take(), + Either::Right(ref mut iter) => iter.next_back(), + } + } + + fn nth_back(&mut self, n: usize) -> Option { + match self.0 { + Either::Left(ref mut opt) if n == 0 => opt.take(), + Either::Left(_) => None, + Either::Right(ref mut iter) => iter.nth_back(n), + } + } +} + +impl<'a, T> std::iter::FusedIterator for Iter<'a, T> {} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + match self.0 { + Either::Left(ref mut opt) => opt.take(), + Either::Right(ref mut iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self.0 { + Either::Left(ref opt) if opt.is_some() => (1, Some(1)), + Either::Left(_) => (0, Some(0)), + Either::Right(ref iter) => iter.size_hint(), + } + } + + fn count(self) -> usize { + match self.0 { + Either::Left(opt) => { + if opt.is_some() { + 1 + } else { + 0 + } + } + Either::Right(iter) => iter.count(), + } + } + + fn last(self) -> Option { + match self.0 { + Either::Left(mut opt) => opt.take(), + Either::Right(iter) => iter.last(), + } + } + + fn nth(&mut self, n: usize) -> Option { + match self.0 { + Either::Left(ref mut opt) if n == 0 => opt.take(), + Either::Left(_) => None, + Either::Right(ref mut iter) => iter.nth(n), + } + } +} + +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + fn next_back(&mut self) -> Option { + match self.0 { + Either::Left(ref mut opt) => opt.take(), + Either::Right(ref mut iter) => iter.next_back(), + } + } + + fn nth_back(&mut self, n: usize) -> Option { + match self.0 { + Either::Left(ref mut opt) if n == 0 => opt.take(), + Either::Left(_) => None, + Either::Right(ref mut iter) => iter.nth_back(n), + } + } +} + +impl<'a, T> std::iter::FusedIterator for IterMut<'a, T> {} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + match self.0 { + Either::Left(ref mut opt) => opt.take(), + Either::Right(ref mut iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self.0 { + Either::Left(ref opt) if opt.is_some() => (1, Some(1)), + Either::Left(_) => (0, Some(0)), + Either::Right(ref iter) => iter.size_hint(), + } + } + + fn count(self) -> usize { + match self.0 { + Either::Left(opt) => { + if opt.is_some() { + 1 + } else { + 0 + } + } + Either::Right(iter) => iter.count(), + } + } + + fn last(self) -> Option { + match self.0 { + Either::Left(mut opt) => opt.take(), + Either::Right(iter) => iter.last(), + } + } + + fn nth(&mut self, n: usize) -> Option { + match self.0 { + Either::Left(ref mut opt) if n == 0 => opt.take(), + Either::Left(_) => None, + Either::Right(ref mut iter) => iter.nth(n), + } + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + match self.0 { + Either::Left(ref mut opt) => opt.take(), + Either::Right(ref mut iter) => iter.next_back(), + } + } + + fn nth_back(&mut self, n: usize) -> Option { + match self.0 { + Either::Left(ref mut opt) if n == 0 => opt.take(), + Either::Left(_) => None, + Either::Right(ref mut iter) => iter.nth_back(n), + } + } +} + +impl std::iter::FusedIterator for IntoIter {} + impl From for OneOrMany { fn from(t: T) -> Self { OneOrMany::from_one(t) @@ -290,3 +560,43 @@ impl From> for OneOrMany { OneOrMany::from_many(t) } } + +#[cfg(test)] +mod tests { + use super::OneOrMany; + + #[test] + fn iter_works() { + let single = OneOrMany::from_one(1); + assert_eq!(single.iter().collect::>(), vec![&1]); + + let many = OneOrMany::from_many(vec![1, 2, 3]); + assert_eq!(many.iter().collect::>(), vec![&1, &2, &3]); + } + + #[test] + fn iter_mut_works() { + let mut single = OneOrMany::from_one(1); + for item in single.iter_mut() { + *item += 1; + } + assert_eq!(single.as_one(), Some(&2)); + + let mut many = OneOrMany::from_many(vec![1, 2, 3]); + for item in many.iter_mut() { + *item += 1; + } + assert_eq!(many.as_many(), Some(&[2, 3, 4][..])); + } + + #[test] + fn into_iter_works() { + let single = OneOrMany::from_one(1); + let v = single.into_iter().collect::>(); + assert_eq!(v, vec![1]); + + let many = OneOrMany::from_many(vec![1, 2, 3]); + let v = many.into_iter().collect::>(); + assert_eq!(v, vec![1, 2, 3]); + } +}