use std::borrow::Cow;
use serde::{Deserialize, Serialize};
use crate::schema::{Key, Map};
mod revision;
pub use revision::Revision;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Header {
pub id: u64,
pub revision: Revision,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Document<'a> {
pub header: Cow<'a, Header>,
pub contents: Cow<'a, [u8]>,
}
impl<'a> Document<'a> {
#[must_use]
pub fn new(id: u64, contents: Cow<'a, [u8]>) -> Self {
let revision = Revision::new(&contents);
Self {
header: Cow::Owned(Header { id, revision }),
contents,
}
}
pub fn with_contents<S: Serialize>(id: u64, contents: &S) -> Result<Self, serde_cbor::Error> {
let contents = Cow::from(serde_cbor::to_vec(contents)?);
Ok(Self::new(id, contents))
}
pub fn contents<D: Deserialize<'a>>(&'a self) -> Result<D, serde_cbor::Error> {
serde_cbor::from_slice(&self.contents)
}
pub fn set_contents<S: Serialize>(&mut self, contents: &S) -> Result<(), serde_cbor::Error> {
self.contents = Cow::from(serde_cbor::to_vec(contents)?);
Ok(())
}
#[must_use]
pub fn create_new_revision(&self, contents: Cow<'a, [u8]>) -> Option<Self> {
self.header
.revision
.next_revision(&contents)
.map(|revision| Self {
header: Cow::Owned(Header {
id: self.header.id,
revision,
}),
contents,
})
}
#[must_use]
pub fn emit(&self) -> Map<(), ()> {
self.emit_key_and_value((), ())
}
#[must_use]
pub fn emit_key<K: Key>(&self, key: K) -> Map<K, ()> {
self.emit_key_and_value(key, ())
}
#[must_use]
pub fn emit_value<Value: Serialize>(&self, value: Value) -> Map<(), Value> {
self.emit_key_and_value((), value)
}
#[must_use]
pub fn emit_key_and_value<K: Key, Value: Serialize>(
&self,
key: K,
value: Value,
) -> Map<K, Value> {
Map::new(self.header.id, key, value)
}
#[must_use]
pub fn to_owned(&self) -> Document<'static> {
Document::<'static> {
header: Cow::Owned(self.header.as_ref().clone()),
contents: Cow::Owned(self.contents.as_ref().to_vec()),
}
}
}
#[test]
fn emissions_tests() -> Result<(), crate::Error> {
use crate::{schema::Map, test_util::Basic};
let doc = Document::with_contents(1, &Basic::default())?;
assert_eq!(doc.emit(), Map::new(doc.header.id, (), ()));
assert_eq!(doc.emit_key(1), Map::new(doc.header.id, 1, ()));
assert_eq!(doc.emit_value(1), Map::new(doc.header.id, (), 1));
assert_eq!(doc.emit_key_and_value(1, 2), Map::new(doc.header.id, 1, 2));
Ok(())
}