Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ pub use self::{
RawRegexRef,
},
document::RawDocument,
document_buf::{BindRawBsonRef, RawDocumentBuf},
document_buf::{BindRawBsonRef, BindValue, RawDocumentBuf},
iter::{RawElement, RawIter},
};

Expand Down
6 changes: 6 additions & 0 deletions src/raw/bson_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,12 @@ impl From<Decimal128> for RawBsonRef<'_> {
}
}

impl<'a> From<&'a RawBson> for RawBsonRef<'a> {
fn from(value: &'a RawBson) -> Self {
value.as_raw_bson_ref()
}
}

/// A BSON binary value referencing raw bytes stored elsewhere.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct RawBinaryRef<'a> {
Expand Down
73 changes: 49 additions & 24 deletions src/raw/document_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,52 +325,77 @@ impl Borrow<RawDocument> for RawDocumentBuf {

/// Types that can be consumed to produce raw bson references valid for a limited lifetime.
/// Conceptually a union between `T: Into<RawBson>` and `T: Into<RawBsonRef>`; if your type
/// implements `Into<RawBsonRef>` it will automatically implement this, but if it only
/// implements `Into<RawBson>` it will need to manually define the trivial impl.
pub trait BindRawBsonRef {
fn bind<F, R>(self, f: F) -> R
where
F: for<'a> FnOnce(RawBsonRef<'a>) -> R;
}
/// implements `Into<RawBsonRef>` it will automatically implement this, but if it
/// implements `Into<RawBson>` it will need to also define an impl of `BindRawBsonRef`:
/// ```
/// # use bson::raw::{BindRawBsonRef, BindValue, RawBson};
/// # struct MyType;
/// # impl Into<RawBson> for MyType {
/// # fn into(self: Self) -> RawBson { todo!() }
/// # }
/// impl BindRawBsonRef for MyType {
/// type Target = BindValue<Self>;
/// }
/// ```
pub trait BindRawBsonRef: Sized {
type Target: BindHelper<Target = Self>;

impl<'a, T: Into<RawBsonRef<'a>>> BindRawBsonRef for T {
fn bind<F, R>(self, f: F) -> R
where
F: for<'b> FnOnce(RawBsonRef<'b>) -> R,
F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
{
f(self.into())
<Self::Target as BindHelper>::bind(self, f)
}
}

impl BindRawBsonRef for RawBson {
fn bind<F, R>(self, f: F) -> R
#[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;
}

/// A struct to use as the `Target` of a [`BindRawBsonRef`] impl for custom types.
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(self.as_raw_bson_ref())
f(target.into().as_raw_bson_ref())
}
}

impl BindRawBsonRef for &RawBson {
fn bind<F, R>(self, f: F) -> R
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<'a> FnOnce(RawBsonRef<'a>) -> R,
F: for<'b> FnOnce(RawBsonRef<'a>) -> R,
{
f(self.as_raw_bson_ref())
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 {
fn bind<F, R>(self, f: F) -> R
where
F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
{
let tmp: RawBson = self.into();
f(tmp.as_raw_bson_ref())
}
type Target = BindValue<Self>;
}
)+
};
Expand Down