You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yuurei/src/state/freeze.rs

92 lines
2.2 KiB

//! 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<User>,
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<UserID, RwLock<User>> = self.users
.iter()
.map(|x| (*x.id(), RwLock::new(x.clone()))).collect();
let mut posts: HashMap<UserID, MaybeVec<RwLock<Post>>> = 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<User> = {
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<UserID, RwLock<User>> = freeze.users
.into_iter()
.map(|x| (*x.id(), RwLock::new(x))).collect();
let mut posts: HashMap<UserID, MaybeVec<RwLock<Post>>> = 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<Freeze> for State
{
#[inline] fn from(from: Freeze) -> Self
{
Self::from_freeze(from)
}
}