diff --git a/src/raw.rs b/src/raw.rs index b1a2c8be..3444a61d 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -143,7 +143,7 @@ pub use self::{ RawRegexRef, }, document::RawDocument, - document_buf::{BindRawBsonRef, RawDocumentBuf}, + document_buf::{BindRawBsonRef, BindValue, RawDocumentBuf}, iter::{RawElement, RawIter}, }; diff --git a/src/raw/bson_ref.rs b/src/raw/bson_ref.rs index 8a72fed5..a2847734 100644 --- a/src/raw/bson_ref.rs +++ b/src/raw/bson_ref.rs @@ -489,6 +489,12 @@ impl From 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> { diff --git a/src/raw/document_buf.rs b/src/raw/document_buf.rs index 2f5c22b9..8c8ee3f4 100644 --- a/src/raw/document_buf.rs +++ b/src/raw/document_buf.rs @@ -325,52 +325,77 @@ impl Borrow for RawDocumentBuf { /// Types that can be consumed to produce raw bson references valid for a limited lifetime. /// Conceptually a union between `T: Into` and `T: Into`; if your type -/// implements `Into` it will automatically implement this, but if it only -/// implements `Into` it will need to manually define the trivial impl. -pub trait BindRawBsonRef { - fn bind(self, f: F) -> R - where - F: for<'a> FnOnce(RawBsonRef<'a>) -> R; -} +/// implements `Into` it will automatically implement this, but if it +/// implements `Into` it will need to also define an impl of `BindRawBsonRef`: +/// ``` +/// # use bson::raw::{BindRawBsonRef, BindValue, RawBson}; +/// # struct MyType; +/// # impl Into for MyType { +/// # fn into(self: Self) -> RawBson { todo!() } +/// # } +/// impl BindRawBsonRef for MyType { +/// type Target = BindValue; +/// } +/// ``` +pub trait BindRawBsonRef: Sized { + type Target: BindHelper; -impl<'a, T: Into>> BindRawBsonRef for T { fn bind(self, f: F) -> R where - F: for<'b> FnOnce(RawBsonRef<'b>) -> R, + F: for<'a> FnOnce(RawBsonRef<'a>) -> R, { - f(self.into()) + ::bind(self, f) } } -impl BindRawBsonRef for RawBson { - fn bind(self, f: F) -> R +#[doc(hidden)] +pub trait BindHelper { + type Target; + fn bind(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(std::marker::PhantomData); +#[doc(hidden)] +pub struct BindRef(std::marker::PhantomData); + +impl> BindHelper for BindValue { + type Target = A; + + fn bind(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(self, f: F) -> R +impl<'a, A: Into> + 'a> BindHelper for BindRef { + type Target = A; + + fn bind(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> + 'a> BindRawBsonRef for T { + type Target = BindRef; +} + +impl BindRawBsonRef for RawBson { + type Target = BindValue; +} + macro_rules! raw_bson_from_impls { ($($t:ty),+$(,)?) => { $( impl BindRawBsonRef for $t { - fn bind(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; } )+ };