use std::borrow::Cow;
use serde::{Deserialize, Serialize};
use crate::schema::{collection, map, 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 collection: collection::Id,
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]>, collection: collection::Id) -> Self {
let revision = Revision::new(&contents);
Self {
header: Cow::Owned(Header { id, revision }),
contents,
collection,
}
}
pub fn with_contents<S: Serialize>(
id: u64,
contents: &S,
collection: collection::Id,
) -> Result<Self, serde_cbor::Error> {
let contents = Cow::from(serde_cbor::to_vec(contents)?);
Ok(Self::new(id, contents, collection))
}
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,
collection: self.collection.clone(),
})
}
#[must_use]
pub fn emit(&self) -> Map<(), ()> {
self.emit_key_and_value((), ())
}
#[must_use]
pub fn emit_key<Key: map::Key>(&self, key: Key) -> Map<Key, ()> {
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<Key: map::Key, Value: Serialize>(
&self,
key: Key,
value: Value,
) -> Map<Key, Value> {
Map::new(self.header.id, key, value)
}
#[must_use]
pub fn to_owned(&self) -> Document<'static> {
Document::<'static> {
collection: self.collection.clone(),
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::{Collection, Map},
test_util::Basic,
};
let doc = Document::with_contents(1, &Basic::default(), Basic::collection_id())?;
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(())
}