//! Frozen, serialisable state use super::*; use futures::prelude::*; /// An immutable image of `State`. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Freeze { users: HashSet, posts: Vec<(UserID, Post)>, } impl Freeze { /// Create a `State` from this freeze /// /// # Notes /// This clones all post and user data, to perform this operation without cloning, use `into_state`. pub fn unfreeze(&self) -> State { let users: HashMap> = self.users .iter() .map(|x| (*x.id(), RwLock::new(x.clone()))).collect(); let mut posts: HashMap>> = HashMap::with_capacity(users.len()); for (id, post) in self.posts.iter() { posts.entry(*id).or_insert_with(move || MaybeVec::new()).push(RwLock::new(post.clone())); } State(Arc::new(Inner{posts: RwLock::new( Posts { users, posts })})) } /// Consume into a new `State`. pub fn into_state(self) -> State { State::from_freeze(self) } } impl State { /// Create a serialisable image from this state pub async fn freeze(&self) -> Freeze { let posts = self.0.posts.read().await; let users: HashSet = { stream::iter(posts.users.iter()) .then(|(_, x)| async move { x.read().await }) .map(|x| x.clone()).collect().await }; let posts: Vec<_> = { stream::iter(posts.posts.iter() .map(|(x, y)| y.into_iter().map(move |z| (x, z))).flatten()) .then(|x| async move { (x.0, x.1.read().await) }) .map(|(&id, post)| (id, post.clone())).collect().await }; Freeze {users, posts} } /// Create `State` from this image pub fn from_freeze(freeze: Freeze) -> Self { let users: HashMap> = freeze.users .into_iter() .map(|x| (*x.id(), RwLock::new(x))).collect(); let mut posts: HashMap>> = HashMap::with_capacity(users.len()); for (id, post) in freeze.posts.into_iter() { posts.entry(id).or_insert_with(move || MaybeVec::new()).push(RwLock::new(post)); } Self(Arc::new(Inner{posts: RwLock::new( Posts { users, posts })})) } } impl From for State { #[inline] fn from(from: Freeze) -> Self { Self::from_freeze(from) } }