Make OneOrMany iterable

This commit is contained in:
asonix 2020-07-26 10:14:52 -05:00
parent bbbae3d951
commit 03ad448fc3
5 changed files with 315 additions and 5 deletions

View file

@ -1,7 +1,7 @@
[package] [package]
name = "activitystreams" name = "activitystreams"
description = "A set of core types and traits for activitystreams data" 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" license = "GPL-3.0"
authors = ["asonix <asonix@asonix.dog>"] authors = ["asonix <asonix@asonix.dog>"]
repository = "https://git.asonix.dog/Aardwolf/activitystreams" repository = "https://git.asonix.dog/Aardwolf/activitystreams"

View file

@ -11,7 +11,7 @@ _A set of Traits and Types that make up the ActivityStreams and ActivityPub spec
First, add ActivityStreams to your dependencies First, add ActivityStreams to your dependencies
```toml ```toml
[dependencies] [dependencies]
activitystreams = "0.7.0-alpha.0" activitystreams = "0.7.0-alpha.2"
``` ```
### Types ### Types

View file

@ -49,7 +49,7 @@ fn main() -> Result<(), Error> {
let v: Vec<ApObject<Page>> = collection let v: Vec<ApObject<Page>> = collection
.take_items() .take_items()
.into_iter() .into_iter()
.map(|o| o.many().into_iter().flatten()) .map(|o| o.into_iter())
.flatten() .flatten()
.filter_map(|any_base| any_base.take_base()) .filter_map(|any_base| any_base.take_base())
.map(|base| base.solidify().and_then(|o| o.extend())) .map(|base| base.solidify().and_then(|o| o.extend()))

View file

@ -11,7 +11,7 @@
//! First, add ActivityStreams to your dependencies //! First, add ActivityStreams to your dependencies
//! ```toml //! ```toml
//! [dependencies] //! [dependencies]
//! activitystreams = "0.7.0-alpha.0" //! activitystreams = "0.7.0-alpha.2"
//! ``` //! ```
//! //!
//! ### Types //! ### 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/). //! 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 activity;
pub mod actor; pub mod actor;

View file

@ -22,7 +22,70 @@ use crate::either::Either;
#[serde(transparent)] #[serde(transparent)]
pub struct OneOrMany<T>(pub(crate) Either<T, Vec<T>>); pub struct OneOrMany<T>(pub(crate) Either<T, Vec<T>>);
/// An iterator over a OneOrMany's borrowed contents
#[derive(Clone, Debug)]
pub struct Iter<'a, T>(Either<Option<&'a T>, std::slice::Iter<'a, T>>);
/// An iterator over a OneOrMany's mutably borrowed contents
#[derive(Debug)]
pub struct IterMut<'a, T>(Either<Option<&'a mut T>, std::slice::IterMut<'a, T>>);
/// An iterator consuming a OneOrMany
#[derive(Clone, Debug)]
pub struct IntoIter<T>(Either<Option<T>, std::vec::IntoIter<T>>);
impl<T> OneOrMany<T> { impl<T> OneOrMany<T> {
/// 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::<Vec<_>>();
/// ```
pub fn into_iter(self) -> IntoIter<T> {
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 /// Create a OneOrMany referencing the existing one
/// ///
/// ```rust /// ```rust
@ -279,6 +342,213 @@ impl<T> OneOrMany<T> {
} }
} }
impl<T> IntoIterator for OneOrMany<T> {
type Item = T;
type IntoIter = IntoIter<T>;
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<Self::Item> {
match self.0 {
Either::Left(ref mut opt) => opt.take(),
Either::Right(ref mut iter) => iter.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
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<Self::Item> {
match self.0 {
Either::Left(mut opt) => opt.take(),
Either::Right(iter) => iter.last(),
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
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<Self::Item> {
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<Self::Item> {
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<Self::Item> {
match self.0 {
Either::Left(ref mut opt) => opt.take(),
Either::Right(ref mut iter) => iter.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
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<Self::Item> {
match self.0 {
Either::Left(mut opt) => opt.take(),
Either::Right(iter) => iter.last(),
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
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<Self::Item> {
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<Self::Item> {
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<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
Either::Left(ref mut opt) => opt.take(),
Either::Right(ref mut iter) => iter.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
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<Self::Item> {
match self.0 {
Either::Left(mut opt) => opt.take(),
Either::Right(iter) => iter.last(),
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
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<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
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<Self::Item> {
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<T> std::iter::FusedIterator for IntoIter<T> {}
impl<T> From<T> for OneOrMany<T> { impl<T> From<T> for OneOrMany<T> {
fn from(t: T) -> Self { fn from(t: T) -> Self {
OneOrMany::from_one(t) OneOrMany::from_one(t)
@ -290,3 +560,43 @@ impl<T> From<Vec<T>> for OneOrMany<T> {
OneOrMany::from_many(t) 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<_>>(), vec![&1]);
let many = OneOrMany::from_many(vec![1, 2, 3]);
assert_eq!(many.iter().collect::<Vec<_>>(), 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::<Vec<_>>();
assert_eq!(v, vec![1]);
let many = OneOrMany::from_many(vec![1, 2, 3]);
let v = many.into_iter().collect::<Vec<_>>();
assert_eq!(v, vec![1, 2, 3]);
}
}