static post suspend works

legacy
Avril 4 years ago
parent 04f35d36d6
commit 4d9441e57b
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -20,6 +20,20 @@ pub struct PostTimestamp
pub last_edit: DateTime<Utc>,
}
impl PostTimestamp
{
/// Create a new timestamp for a new post
pub fn new() -> Self
{
let now = Utc::now();
Self {
opened: now.clone(),
closed: None,
last_edit: now,
}
}
}
impl Hash for PostTimestamp {
fn hash<H: Hasher>(&self, state: &mut H) {
self.opened.hash(state);
@ -61,6 +75,26 @@ pub struct Static
hash: crypto::sha256::Sha256Hash,
}
impl Static
{
/// Compute the hash for this instance
pub fn into_hashed(mut self) -> Self
{
self.hash = Default::default();
let bytes = serde_cbor::to_vec(&self).expect("Failed to serialise static post to CBOR");
Self {
hash: crypto::sha256::compute_slice(&bytes),
..self
}
}
/// Validate the internal hash of this instance
pub fn validate_hash(&self) -> bool
{
self.clone().into_hashed().hash == self.hash
}
}
use suspend::{
Suspendable,
SuspendStream,
@ -81,3 +115,42 @@ impl Suspendable for Static
input.try_get("post-static").ok_or(suspend::Error::BadObject)
}
}
#[cfg(test)]
mod tests
{
use super::*;
#[tokio::test]
async fn static_post_ser()
{
let mut output = suspend::MemorySsuspendStream::new();
let post1 = Static {
id: identity::PostID::new(),
user: Default::default(),
title: None,
karada: "hello world".to_owned(),
timestamp: PostTimestamp::new(),
hash: Default::default(),
}.into_hashed();
let post1c = post1.clone();
assert!(post1.validate_hash());
post1.suspend(&mut output).await.expect("Suspend failed");
let buffer = output.buffer().clone();
let post2 = Static::load(&mut output).await.expect("Suspend load failed");
assert_eq!(post1c, post2);
assert!(post1c.validate_hash());
assert!(post2.validate_hash());
let buffer2 = suspend::oneshot(post2.clone()).await.expect("Oneshot failed");
assert_eq!(&buffer2[..], &buffer[..]);
let post3: Static = suspend::single(buffer2).await.expect("Single failed");
assert!(post3.validate_hash());
assert_eq!(post3, post2);
}
}

@ -70,7 +70,7 @@ impl Object
}
true
}
/// Try to get a value of type `T` from `name`.
pub fn get<'a, T>(&'a mut self, name: impl Borrow<str>) -> Option<T>
where T: Deserialize<'a>
@ -165,26 +165,47 @@ impl Object
}
/// Consume into the data
#[deprecated = "Invalid ABI"] fn into_bytes(self) -> Box<[u8]>
pub fn into_bytes(self) -> Box<[u8]>
{
let mut output = Vec::new(); //TOOO: Get cap
debug_assert!(self.validate(), "passing invalid object to serialise");
unsafe {
output.extend_from_slice(bytes::refer(&self.data_instances.len()));
for (name, Range{start, end}) in self.data_instances.into_iter() {
let name = name.as_bytes();
macro_rules! bin {
($bytes:expr) => {
{
let bytes = $bytes;
output.extend_from_slice(bytes.as_ref());
}
};
(usize $value:expr) => {
{
use std::convert::TryInto;
use byteorder::{
WriteBytesExt,
LittleEndian,
};
let val: u64 = $value.try_into().expect("Value could not fit into `u64`");
WriteBytesExt::write_u64::<LittleEndian>(&mut output,val).expect("Failed to append `u64` to output buffer");
}
};
}
output.extend_from_slice(bytes::refer(&name.len()));
output.extend_from_slice(name);
bin!(usize self.data_instances.len());
for (name, &Range{start, end}) in self.data_instances.iter() {
let name = name.as_bytes();
output.extend_from_slice(bytes::refer(&start));
output.extend_from_slice(bytes::refer(&end));
}
bin!(usize name.len());
bin!(name);
bin!(usize start);
bin!(usize end);
}
bin!(usize self.data.len()); //for additional checks
output.extend(self.data);
output.into_boxed_slice()
}
@ -329,6 +350,14 @@ impl fmt::Display for Error
}
}
impl From<io::Error> for Error
{
#[inline] fn from(from: io::Error) -> Self
{
Self::IO(from)
}
}
/// A suspendable type, that can save and reload its data atomically
#[async_trait]
@ -338,11 +367,154 @@ pub trait Suspendable: Sized
async fn load<S: SuspendStream + Send+ Sync+?Sized>(from: &mut S) -> Result<Self, Error>;
}
/// An in-memory `SuspendStream`.
#[derive(Debug, Clone)]
pub struct MemorySsuspendStream(Vec<u8>);
impl MemorySsuspendStream
{
/// Create a new empty instance
pub fn new() -> Self
{
Self(Vec::new())
}
/// Create from a vector of bytes
pub fn from_bytes(from: impl Into<Vec<u8>>) -> Self
{
Self(from.into())
}
/// Create from a slice of bytes
pub fn from_slice(from: impl AsRef<[u8]>) -> Self
{
Self(Vec::from(from.as_ref()))
}
/// Return the internal bytes
pub fn into_bytes(self) -> Vec<u8>
{
self.0
}
/// The internal buffer
pub fn buffer(&self) -> &Vec<u8>
{
&self.0
}
/// The internal buffer
pub fn buffer_mut(&mut self) -> &mut Vec<u8>
{
&mut self.0
}
}
impl AsRef<[u8]> for MemorySsuspendStream
{
fn as_ref(&self) -> &[u8]
{
&self.0[..]
}
}
impl AsMut<[u8]> for MemorySsuspendStream
{
fn as_mut(&mut self) -> &mut [u8]
{
&mut self.0[..]
}
}
impl From<Vec<u8>> for MemorySsuspendStream
{
#[inline] fn from(from: Vec<u8>) -> Self
{
Self(from.into())
}
}
impl From<Box<[u8]>> for MemorySsuspendStream
{
fn from(from: Box<[u8]>) -> Self
{
Self::from_bytes(from)
}
}
impl From<MemorySsuspendStream> for Box<[u8]>
{
fn from(from: MemorySsuspendStream) -> Self
{
from.0.into()
}
}
impl From<MemorySsuspendStream> for Vec<u8>
{
#[inline] fn from(from: MemorySsuspendStream) -> Self
{
from.0
}
}
#[async_trait]
impl SuspendStream for MemorySsuspendStream
{
async fn get_object(&mut self) -> Result<Option<Object>, Error> {
if self.0.len() ==0 {
return Ok(None);
}
let mut ptr = &self.0[..];
let vl = Object::from_stream(&mut ptr).await?;
let diff = (ptr.as_ptr() as usize) - ((&self.0[..]).as_ptr() as usize);
self.0.drain(0..diff);
Ok(Some(vl))
}
async fn set_object(&mut self, obj: Object) -> Result<(), Error> {
obj.into_stream(&mut self.0).await?;
Ok(())
}
}
/*
pub struct SuspenceState<T>
where T: Suspendable
/// Suspend a single object to memory
pub async fn oneshot<T: Suspendable>(value: T) -> Result<Vec<u8>, Error>
{
let mut output = MemorySsuspendStream::new();
value.suspend(&mut output).await?;
Ok(output.into_bytes())
}
_phantom: PhantomData<T>,
}*/
/// Load a single value from memory
pub async fn single<T: Suspendable>(from: impl AsRef<[u8]>) -> Result<T, Error>
{
struct BorrowedStream<'a>(&'a [u8]);
#[async_trait]
impl<'a> SuspendStream for BorrowedStream<'a>
{
async fn get_object(&mut self) -> Result<Option<Object>, Error> {
if self.0.len() ==0 {
return Ok(None);
}
let mut ptr = &self.0[..];
let vl = Object::from_stream(&mut ptr).await?;
let diff = (ptr.as_ptr() as usize) - ((&self.0[..]).as_ptr() as usize);
self.0 = &self.0[diff..];
Ok(Some(vl))
}
async fn set_object(&mut self, _: Object) -> Result<(), Error> {
panic!("Cannot write to borrowed stream")
}
}
let bytes = from.as_ref();
let mut stream = BorrowedStream(bytes);
T::load(&mut stream).await
}

Loading…
Cancel
Save