pub use uncollate_macro::Uncollate;
pub trait Uncollate<T> {
fn uncollate(self) -> T;
}
pub trait Collated<T: Uncollated> {
fn uncollate_one(self, uncollated: &mut T);
}
pub trait Uncollated: Default {}
impl<U: Uncollated, C: Collated<U>, T: IntoIterator<Item = C>> Uncollate<U> for T {
fn uncollate(self) -> U {
let mut uncollated: U = Default::default();
for collated in self {
collated.uncollate_one(&mut uncollated);
}
uncollated
}
}
#[macro_export]
macro_rules! uncollate {
(&$vec:ident.$field:ident) => {
(&$vec).into_iter().map(|elem| &elem.$field).collect::<::std::vec::Vec<_>>()
};
(&$vec:ident.$field:ident, $t:ty) => {
(&$vec).into_iter().map(|elem| &elem.$field).collect::<$t>()
};
(&mut $vec:ident.$field:ident) => {
(&mut $vec).into_iter().map(|elem| &mut elem.$field).collect::<::std::vec::Vec<_>>()
};
(&mut $vec:ident.$field:ident, $t:ty) => {
(&mut $vec).into_iter().map(|elem| &mut elem.$field).collect::<$t>()
};
}
#[macro_export]
macro_rules! uncollate_req {
(&$vec:ident.$field:ident) => {
(&$vec).into_iter().map(|elem| ::std::option::Option::ok_or(elem.$field.as_ref(), "value must not be None"))
.collect::<::std::result::Result<::std::vec::Vec<_>,_>>()
};
(&$vec:ident.$field:ident, $t:ty) => {
(&$vec).into_iter().map(|elem| ::std::option::Option::ok_or(elem.$field.as_ref(), "value must not be None"))
.collect::<::std::result::Result<$t,_>>()
};
(&mut $vec:ident.$field:ident) => {
(&mut $vec).into_iter().map(|elem| ::std::option::Option::ok_or(elem.$field.as_mut(), "value must not be None"))
.collect::<::std::result::Result<::std::vec::Vec<_>,_>>()
};
(&mut $vec:ident.$field:ident, $t:ty) => {
(&mut $vec).into_iter().map(|elem| ::std::option::Option::ok_or(elem.$field.as_mut(), "value must not be None"))
.collect::<::std::result::Result<$t,_>>()
};
}
#[cfg(test)]
mod tests {
#[test]
pub fn test_uncollate_by_ref() {
struct Test {
a: String,
}
let test = vec![
Test { a: "Hello".into() },
Test { a: "Goodbye".into() }
];
let uncol = uncollate!(&test.a);
assert_eq!(vec![&test[0].a, &test[1].a], uncol);
}
#[test]
pub fn test_uncollate_req() {
struct Test {
a: Option<String>,
}
let test = vec![
Test { a: Some("Hello".into())},
Test { a: None}
];
let uncol = uncollate_req!(&test.a);
assert!(uncol.is_err());
}
}