use_prelude!();
use crate::error::{DittoError, ErrorKind};
#[derive(Debug, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct DocumentId {
pub(crate) bytes: Vec<u8>,
}
impl DocumentId {
pub fn new<V: ::serde::Serialize>(value: &V) -> Result<Self, DittoError> {
let cbor_bytes = ::serde_cbor::to_vec(value).unwrap();
let bytes = validate_doc_id_cbor_bytes(cbor_bytes)?;
Ok(Self { bytes })
}
pub fn to_query_compatible(
&self,
string_primitive_fmt: ffi_sdk::StringPrimitiveFormat,
) -> String {
let str_boxed = ffi_sdk::ditto_document_id_query_compatible(
self.bytes.as_slice().into(),
string_primitive_fmt,
);
str_boxed.into_string()
}
pub fn value(&self) -> ::serde_cbor::Value {
self.to_cbor()
}
pub fn to_cbor(&self) -> ::serde_cbor::Value {
::serde_cbor::from_slice(&self.bytes[..]).expect("DocumentId can be represented as CBOR")
}
}
impl From<Vec<u8>> for DocumentId {
fn from(bytes: Vec<u8>) -> Self {
Self { bytes }
}
}
impl From<Box<[u8]>> for DocumentId {
fn from(bytes: Box<[u8]>) -> Self {
Self {
bytes: bytes.into(),
}
}
}
impl From<&[u8]> for DocumentId {
fn from(slice: &[u8]) -> Self {
Self {
bytes: slice.to_owned().to_vec(),
}
}
}
impl AsRef<[u8]> for DocumentId {
fn as_ref(&self) -> &[u8] {
&self.bytes[..]
}
}
impl std::fmt::Display for DocumentId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.to_query_compatible(ffi_sdk::StringPrimitiveFormat::WithoutQuotes)
)
}
}
impl serde::Serialize for DocumentId {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut deserializer = serde_cbor::Deserializer::from_slice(&self.bytes[..]);
serde_transcode::transcode(&mut deserializer, serializer)
}
}
impl<'de> serde::de::Deserialize<'de> for DocumentId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let cbor_bytes =
serde_cbor::to_vec(&serde_cbor::Value::deserialize(deserializer)?).unwrap();
let bytes = validate_doc_id_cbor_bytes(cbor_bytes)
.expect("document id bytes are valid when deserializing");
Ok(Self { bytes })
}
}
fn validate_doc_id_cbor_bytes(bytes: Vec<u8>) -> Result<Vec<u8>, DittoError> {
use safer_ffi::prelude::{AsOut, ManuallyDropMut};
let mut out_cbor_slot = None;
let out_cbor = out_cbor_slot.manually_drop_mut().as_out();
{
let res = ffi_sdk::ditto_validate_document_id(bytes[..].into(), out_cbor);
if res != 0 {
return Err(DittoError::from_ffi(ErrorKind::Internal));
}
}
Ok(match out_cbor_slot {
None => bytes,
Some(cbor_boxed_slice) => cbor_boxed_slice.to::<Box<[u8]>>().into(),
})
}