use_prelude!();
use std::{borrow::BorrowMut, time::SystemTime};
use ffi_sdk::PathAccessorType;
use serde::{de::DeserializeOwned, Serialize};
use super::type_traits::MutableValue;
use crate::error::{DittoError, ErrorKind};
pub trait DittoDocument {
fn id(&self) -> DocumentId;
fn to_cbor(&self) -> Result<serde_cbor::Value, DittoError>;
fn get<V: DeserializeOwned>(&self, path: &str) -> Result<V, DittoError>;
fn typed<T: DeserializeOwned>(&self) -> Result<T, DittoError>;
}
pub trait DittoMutDocument: DittoDocument {
fn get_mut<V: MutableValue>(&mut self, path: &str) -> Result<V, DittoError>;
fn set<V: Serialize>(&mut self, path: &str, val: V) -> Result<(), DittoError>;
fn set_as_default<V: Serialize>(&mut self, path: &str, val: V) -> Result<(), DittoError>;
fn remove(&mut self, path: &str) -> Result<(), DittoError>;
fn increment(&mut self, path: &str, amount: f64) -> Result<(), DittoError>;
}
impl<T: Borrow<ffi_sdk::Document>> DittoDocument for T {
fn id(&self) -> DocumentId {
let id_slice = ffi_sdk::ditto_document_id(self.borrow());
let id = id_slice.to_vec().into();
id
}
fn to_cbor(&self) -> Result<serde_cbor::Value, DittoError> {
let c_bytes = ffi_sdk::ditto_document_cbor(self.borrow());
let result = serde_cbor::from_slice(c_bytes.as_slice())
.map_err(|e| DittoError::new(ErrorKind::InvalidInput, e));
result
}
fn get<V: DeserializeOwned>(&self, path: &str) -> Result<V, DittoError> {
get_internal(self.borrow(), path, PathAccessorType::Any)
}
fn typed<V: DeserializeOwned>(&self) -> Result<V, DittoError> {
let c_bytes = ffi_sdk::ditto_document_cbor(self.borrow());
let result = serde_cbor::from_slice::<V>(c_bytes.as_slice())
.map_err(|e| DittoError::new(ErrorKind::InvalidInput, e));
result
}
}
fn get_internal<V: DeserializeOwned>(
doc: &ffi_sdk::Document,
path: &str,
path_type: PathAccessorType,
) -> Result<V, DittoError> {
let c_path = char_p::new(path);
let value = ::serde_cbor::from_slice(
::ffi_sdk::ditto_document_get_cbor_with_path_type(doc, c_path.as_ref(), path_type)
.ok_or(ErrorKind::InvalidInput)?
.ok_or(ErrorKind::NonExtant)?
.as_slice(),
)
.map_err(|e| DittoError::new(ErrorKind::InvalidInput, e))?;
Ok(value)
}
impl<T: BorrowMut<ffi_sdk::Document>> DittoMutDocument for T {
fn get_mut<V: MutableValue>(&mut self, path: &str) -> Result<V> {
let base_value: V::BaseType = self.get(path)?;
let doc = self.borrow_mut();
let c_key = char_p::new(path);
V::mutable_version(base_value, doc, c_key)
}
fn set<V: Serialize>(&mut self, path: &str, val: V) -> Result<(), DittoError> {
let c_str = char_p::new(path);
let cbor: Vec<u8> =
serde_cbor::to_vec(&val).map_err(|e| DittoError::new(ErrorKind::InvalidInput, e))?;
let status = {
ffi_sdk::ditto_document_set_cbor(
self.borrow_mut(),
c_str.as_ref(),
cbor.as_slice().into(),
)
};
if status != 0 {
Err(DittoError::from_ffi(ErrorKind::InvalidInput))
} else {
Ok(())
}
}
fn set_as_default<V: Serialize>(&mut self, path: &str, val: V) -> Result<(), DittoError> {
let c_str = char_p::new(path);
let cbor: Vec<u8> =
serde_cbor::to_vec(&val).map_err(|e| DittoError::new(ErrorKind::InvalidInput, e))?;
let timestamp = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
Ok(n) => n.as_secs(),
Err(e) => return Err(DittoError::new(ErrorKind::Internal, e)),
};
let status = {
ffi_sdk::ditto_document_set_cbor_with_timestamp(
self.borrow_mut(),
c_str.as_ref(),
cbor.as_slice().into(),
timestamp as u32,
)
};
if status != 0 {
Err(DittoError::from_ffi(ErrorKind::InvalidInput))
} else {
Ok(())
}
}
fn remove(&mut self, path: &str) -> Result<(), DittoError> {
let pointer = char_p::new(path);
let status = ffi_sdk::ditto_document_remove(self.borrow_mut(), pointer.as_ref());
if status != 0 {
Err(DittoError::from_ffi(ErrorKind::InvalidInput))
} else {
Ok(())
}
}
fn increment(&mut self, path: &str, amount: f64) -> Result<(), DittoError> {
let pointer = char_p::new(path);
let status = {
ffi_sdk::ditto_document_increment_counter(self.borrow_mut(), pointer.as_ref(), amount)
};
if status != 0 {
Err(DittoError::from_ffi(ErrorKind::InvalidInput))
} else {
Ok(())
}
}
}