use std::{
borrow::{Borrow, Cow},
convert::TryFrom,
ops::Deref,
};
use crate::{
raw::{doc_writer::DocWriter, CStr},
Document,
};
use super::{bson::RawBson, iter::Iter, RawBsonRef, RawDocument, RawIter, Result};
#[derive(Clone, PartialEq)]
pub struct RawDocumentBuf {
data: Vec<u8>,
}
impl RawDocumentBuf {
pub fn new() -> Self {
let mut data = Vec::new();
DocWriter::open(&mut data);
Self { data }
}
pub fn from_bytes(data: Vec<u8>) -> Result<Self> {
let _ = RawDocument::from_bytes(data.as_slice())?;
Ok(Self { data })
}
pub fn from_reader<R: std::io::Read>(reader: R) -> Result<Self> {
let buf = crate::raw::reader_to_vec(reader)?;
Self::from_bytes(buf)
}
pub fn iter(&self) -> Iter<'_> {
Iter::new(self)
}
pub fn iter_elements(&self) -> RawIter<'_> {
RawIter::new(self)
}
pub fn into_bytes(self) -> Vec<u8> {
self.data
}
pub fn append(&mut self, key: impl AsRef<CStr>, value: impl BindRawBsonRef) {
self.data.pop();
let key = key.as_ref();
value.bind(|value_ref| {
let mut writer = DocWriter::resume(&mut self.data, 0);
writer.append_key(value_ref.element_type(), key);
value_ref.append_to(writer.buffer());
});
}
}
impl<K: AsRef<CStr>, B: BindRawBsonRef> FromIterator<(K, B)> for RawDocumentBuf {
fn from_iter<T: IntoIterator<Item = (K, B)>>(iter: T) -> Self {
let mut buf = RawDocumentBuf::new();
for (k, v) in iter {
buf.append(k, v);
}
buf
}
}
impl Default for RawDocumentBuf {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for RawDocumentBuf {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(super::serde::OwnedOrBorrowedRawDocument::deserialize(deserializer)?.into_owned())
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for RawDocumentBuf {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let doc: &RawDocument = self.deref();
doc.serialize(serializer)
}
}
impl std::fmt::Debug for RawDocumentBuf {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RawDocumentBuf")
.field("data", &hex::encode(&self.data))
.finish()
}
}
impl From<RawDocumentBuf> for Cow<'_, RawDocument> {
fn from(rd: RawDocumentBuf) -> Self {
Cow::Owned(rd)
}
}
impl<'a> From<&'a RawDocumentBuf> for Cow<'a, RawDocument> {
fn from(rd: &'a RawDocumentBuf) -> Self {
Cow::Borrowed(rd.as_ref())
}
}
impl TryFrom<&Document> for RawDocumentBuf {
type Error = crate::error::Error;
fn try_from(doc: &Document) -> std::result::Result<Self, Self::Error> {
let mut out = vec![];
doc.append_to(&mut out)?;
RawDocumentBuf::from_bytes(out)
}
}
impl TryFrom<Document> for RawDocumentBuf {
type Error = crate::error::Error;
fn try_from(doc: Document) -> std::result::Result<Self, Self::Error> {
RawDocumentBuf::try_from(&doc)
}
}
impl<'a> IntoIterator for &'a RawDocumentBuf {
type IntoIter = Iter<'a>;
type Item = Result<(&'a CStr, RawBsonRef<'a>)>;
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
impl AsRef<RawDocument> for RawDocumentBuf {
fn as_ref(&self) -> &RawDocument {
RawDocument::new_unchecked(&self.data)
}
}
impl Deref for RawDocumentBuf {
type Target = RawDocument;
fn deref(&self) -> &Self::Target {
RawDocument::new_unchecked(&self.data)
}
}
impl Borrow<RawDocument> for RawDocumentBuf {
fn borrow(&self) -> &RawDocument {
self.deref()
}
}
#[allow(missing_docs)]
pub trait BindRawBsonRef: Sized {
type Target: BindHelper<Target = Self>;
fn bind<F, R>(self, f: F) -> R
where
F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
{
<Self::Target as BindHelper>::bind(self, f)
}
}
#[doc(hidden)]
pub trait BindHelper {
type Target;
fn bind<F, R>(target: Self::Target, f: F) -> R
where
F: for<'b> FnOnce(RawBsonRef<'b>) -> R;
}
pub struct BindValue<A>(std::marker::PhantomData<A>);
#[doc(hidden)]
pub struct BindRef<A>(std::marker::PhantomData<A>);
impl<A: Into<RawBson>> BindHelper for BindValue<A> {
type Target = A;
fn bind<F, R>(target: Self::Target, f: F) -> R
where
F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
{
f(target.into().as_raw_bson_ref())
}
}
impl<'a, A: Into<RawBsonRef<'a>> + 'a> BindHelper for BindRef<A> {
type Target = A;
fn bind<F, R>(target: Self::Target, f: F) -> R
where
F: for<'b> FnOnce(RawBsonRef<'a>) -> R,
{
f(target.into())
}
}
impl<'a, T: Into<RawBsonRef<'a>> + 'a> BindRawBsonRef for T {
type Target = BindRef<T>;
}
impl BindRawBsonRef for RawBson {
type Target = BindValue<Self>;
}
macro_rules! raw_bson_from_impls {
($($t:ty),+$(,)?) => {
$(
impl BindRawBsonRef for $t {
type Target = BindValue<Self>;
}
)+
};
}
raw_bson_from_impls! {
&crate::binary::Vector,
crate::Binary,
crate::DbPointer,
super::RawArrayBuf,
RawDocumentBuf,
super::RawJavaScriptCodeWithScope,
crate::Regex,
String,
crate::binary::Vector,
}