|
|
|
@ -1,6 +1,8 @@
|
|
|
|
|
//! Frozen, serialisable state
|
|
|
|
|
use super::*;
|
|
|
|
|
use futures::prelude::*;
|
|
|
|
|
use std::io;
|
|
|
|
|
use tokio::prelude::*;
|
|
|
|
|
|
|
|
|
|
/// An immutable image of `State`.
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
|
|
@ -10,6 +12,73 @@ pub struct Freeze
|
|
|
|
|
posts: Vec<(UserID, Post)>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reading and writing state
|
|
|
|
|
//TODO: Compression
|
|
|
|
|
impl Freeze
|
|
|
|
|
{
|
|
|
|
|
/// Serialise this instance into an output synchronously
|
|
|
|
|
pub fn write_sync(&self, output: impl io::Write) -> eyre::Result<()>
|
|
|
|
|
{
|
|
|
|
|
serde_cbor::to_writer(output, self)
|
|
|
|
|
.wrap_err(eyre!("Failed to write (sync) to output"))
|
|
|
|
|
}
|
|
|
|
|
/// Serialise this instance into an output asynchronously
|
|
|
|
|
///
|
|
|
|
|
/// # Notes
|
|
|
|
|
/// This function serialises to a heap buffer first
|
|
|
|
|
pub async fn write_async(&self, mut output: impl tokio::io::AsyncWrite + Unpin) -> eyre::Result<()>
|
|
|
|
|
{
|
|
|
|
|
let buf = serde_cbor::to_vec(self)
|
|
|
|
|
.wrap_err(eyre!("Failed to serialise to buffer"))?;
|
|
|
|
|
|
|
|
|
|
output.write_all(&buf[..]).await
|
|
|
|
|
.wrap_err(eyre!("Failed to write buffer to output stream"))?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Deserialise an instance from an input synchronously
|
|
|
|
|
pub fn read_sync(input: impl io::Read) -> eyre::Result<Self>
|
|
|
|
|
{
|
|
|
|
|
serde_cbor::from_reader(input)
|
|
|
|
|
.wrap_err(eyre!("Failed to read (sync) from input"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Deserialise an instance from an input asynchronously
|
|
|
|
|
///
|
|
|
|
|
/// # Notes
|
|
|
|
|
/// This function reads the entire input stream into a heap allocated buffer first
|
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
/// If the buffer size exceeds `defaults::MAX_IMAGE_READ_SIZE`.
|
|
|
|
|
pub async fn read_async(mut input: impl tokio::io::AsyncRead + Unpin) -> eyre::Result<Self>
|
|
|
|
|
{
|
|
|
|
|
let whole = {
|
|
|
|
|
let mut whole = Vec::new();
|
|
|
|
|
let mut buffer = [0u8; 4096];
|
|
|
|
|
let mut read;
|
|
|
|
|
let mut done =0;
|
|
|
|
|
while { read = input.read(&mut buffer[..]).await.wrap_err(eyre!("Failed to read from input"))?; read > 0 }
|
|
|
|
|
{
|
|
|
|
|
whole.extend_from_slice(&buffer[..read]);
|
|
|
|
|
done+=read;
|
|
|
|
|
if defaults::MAX_IMAGE_READ_SIZE > 0 { //constant fn should
|
|
|
|
|
if done > defaults::MAX_IMAGE_READ_SIZE {
|
|
|
|
|
Err::<!, _>(eyre!("Image read exceeded max read size"))
|
|
|
|
|
.with_section(|| done.to_string().header("Current size is"))
|
|
|
|
|
.with_note(|| defaults::MAX_IMAGE_READ_SIZE.to_string().header("Max size is"))
|
|
|
|
|
.expect("Image read fatal"); //panic with this instance
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
whole
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
serde_cbor::from_slice(&whole)
|
|
|
|
|
.wrap_err(eyre!("Failed to deserialise buffer"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Freeze
|
|
|
|
|
{
|
|
|
|
|
/// Create a `State` from this freeze
|
|
|
|
@ -39,6 +108,15 @@ impl Freeze
|
|
|
|
|
{
|
|
|
|
|
State::from_freeze(self)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Try to consume this `State` into a `Freeze`.
|
|
|
|
|
///
|
|
|
|
|
/// # Fails
|
|
|
|
|
/// See `State::try_into_freeze()`.
|
|
|
|
|
#[inline] pub fn try_from_state(state: State) -> Result<Self, State>
|
|
|
|
|
{
|
|
|
|
|
state.try_into_freeze()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl State
|
|
|
|
@ -62,6 +140,32 @@ impl State
|
|
|
|
|
Freeze {users, posts}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Try to consume into a `Freeze`.
|
|
|
|
|
///
|
|
|
|
|
/// # Result
|
|
|
|
|
/// This method fails if there are more than one shared reference to the state
|
|
|
|
|
pub fn try_into_freeze(self) -> Result<Freeze, Self>
|
|
|
|
|
{
|
|
|
|
|
match Arc::try_unwrap(self.0) {
|
|
|
|
|
Ok(freeze) => {
|
|
|
|
|
let posts = freeze.posts.into_inner();
|
|
|
|
|
let users: HashSet<User> = {
|
|
|
|
|
posts.users.into_iter()
|
|
|
|
|
.map(|(_, x)| x.into_inner()).collect()
|
|
|
|
|
};
|
|
|
|
|
let posts: Vec<_> = {
|
|
|
|
|
posts.posts.into_iter()
|
|
|
|
|
.map(|(x, y)| y.into_iter().map(move |z| (x, z.into_inner()))).flatten()
|
|
|
|
|
//.map(|x| (x.0, x.1.into_inner()) )
|
|
|
|
|
.map(|(id, post)| (id, post)).collect()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(Freeze {users, posts})
|
|
|
|
|
},
|
|
|
|
|
Err(e) => Err(Self(e))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create `State` from this image
|
|
|
|
|
pub fn from_freeze(freeze: Freeze) -> Self
|
|
|
|
|
{
|
|
|
|
@ -89,3 +193,13 @@ impl From<Freeze> for State
|
|
|
|
|
Self::from_freeze(from)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TryFrom<State> for Freeze
|
|
|
|
|
{
|
|
|
|
|
type Error = State;
|
|
|
|
|
|
|
|
|
|
#[inline] fn try_from(from: State) -> Result<Self, Self::Error>
|
|
|
|
|
{
|
|
|
|
|
from.try_into_freeze()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|