//! Helper traits and stuff for working with lists and iterators of objects // Re-export itertools for convenience pub use itertools; use crate::{data, insert, model, update, ID}; use itertools::Itertools; use std::collections::HashMap; pub trait GetParent { fn get_parent(&self) -> ID; } macro_rules! impl_get_parent { ($($struct:ty),+) => { $( impl GetParent for $struct { fn get_parent(&self) -> ID { self.object } } impl GetParent for &$struct { fn get_parent(&self) -> ID { self.object } } impl GetParent for &&$struct { fn get_parent(&self) -> ID { self.object } } )+ } } impl_get_parent!( data::Value, data::Relation, model::RelationModel, model::PropertyModel); pub trait GetModelID { fn get_model_id(&self) -> ID; } macro_rules! impl_get_model_id { ($($struct:ty),+) => { $( impl GetModelID for $struct { fn get_model_id(&self) -> ID { self.model } } impl GetModelID for &$struct { fn get_model_id(&self) -> ID { self.model } } impl GetModelID for &&$struct { fn get_model_id(&self) -> ID { self.model } } )+ } } impl_get_model_id!( data::Object, data::Value, data::Relation, insert::InsertRel, insert::InsertValue, insert::InsertObj, update::UpsertRelation, update::UpsertValue); // This would be nice, but doesn't work // // pub struct FilterOfParent<'a, S: 'a> { iter: S, parent: ID, marker : std::marker::PhantomData<&'a S> } // // // impl<'a, V: GetParent + 'a, S: Iterator> Iterator for FilterOfParent { // // type Item = &'a V; // // // // #[inline] // // fn next(&mut self) -> Option { // // let parent = self.parent; // // self.iter.find(|x| x.get_parent() == parent) // // } // // } // // impl<'a, V: GetParent + 'a, S: Iterator> Iterator for FilterOfParent<'a, S> { // type Item = V; // // #[inline] // fn next(&mut self) -> Option { // let parent = self.parent; // self.iter.find(|x| x.get_parent() == parent) // } // } // // pub trait WhereParent<'a>: Sized { // fn where_parent(self, id: ID) -> FilterOfParent<'a, Self>; // } // // impl<'a, V : 'a, S : 'a + Iterator> WhereParent<'a> for S { // fn where_parent(self, id: ID) -> FilterOfParent<'a, Self> { // FilterOfParent { iter: self, parent: id, marker: std::marker::PhantomData } // } // } pub trait GroupByParent<'a, T: 'a + GetParent>: Sized { fn group_by_parent(self) -> HashMap>; } impl<'a, T: 'a + GetParent, S: IntoIterator> GroupByParent<'a, T> for S { #[inline] fn group_by_parent(self) -> HashMap> { self.into_iter().into_group_map_by(|v| v.get_parent()) } } pub trait GroupByModel<'a, T: 'a + GetModelID>: Sized { fn group_by_model(self) -> HashMap>; } impl<'a, T: 'a + GetModelID, S: IntoIterator> GroupByModel<'a, T> for S { #[inline] fn group_by_model(self) -> HashMap> { self.into_iter().into_group_map_by(|v| v.get_model_id()) } } #[cfg(test)] mod tests { use crate::helpers::{GetParent, GroupByParent}; use crate::id::random_id; use crate::ID; #[derive(Debug, PartialEq, Eq)] struct Child(ID, &'static str); impl GetParent for Child { fn get_parent(&self) -> ID { self.0 } } #[test] fn group_vec() { let parent1 = random_id(); let parent2 = random_id(); let vec = vec![ Child(parent1, "A"), Child(parent2, "C"), Child(parent1, "B"), Child(parent2, "D"), ]; let mut grouped = vec.group_by_parent(); assert_eq!(2, grouped.len()); assert_eq!( grouped.remove(&parent1).unwrap(), vec![Child(parent1, "A"), Child(parent1, "B"),] ); assert_eq!( grouped.remove(&parent2).unwrap(), vec![Child(parent2, "C"), Child(parent2, "D"),] ); } #[test] fn group_iter() { let parent1 = random_id(); let parent2 = random_id(); let vec = vec![ Child(parent1, "A"), Child(parent2, "C"), Child(parent1, "B"), Child(parent2, "D"), ]; let mut grouped = vec.into_iter().group_by_parent(); assert_eq!(2, grouped.len()); assert_eq!( grouped.remove(&parent1).unwrap(), vec![Child(parent1, "A"), Child(parent1, "B"),] ); assert_eq!( grouped.remove(&parent2).unwrap(), vec![Child(parent2, "C"), Child(parent2, "D"),] ); } // #[test] // fn count_where_parent() { // let parent1 = random_id(); // let parent2 = random_id(); // // let vec = vec![ // Child(parent1, "A"), // Child(parent2, "C"), // Child(parent1, "B"), // Child(parent2, "D"), // ]; // // let _ = vec.iter().where_parent(parent2).next(); // } }