Skip to content

Commit c038fb5

Browse files
authored
RUST-1887 Convince append to be more accepting (#541)
1 parent aa95676 commit c038fb5

File tree

3 files changed

+86
-26
lines changed

3 files changed

+86
-26
lines changed

src/raw/array_buf.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ use serde::{Deserialize, Serialize};
88

99
use crate::{RawArray, RawBsonRef, RawDocumentBuf};
1010

11-
use super::{bson::RawBson, serde::OwnedOrBorrowedRawArray, RawArrayIter};
11+
use super::{document_buf::BindRawBsonRef, serde::OwnedOrBorrowedRawArray, RawArrayIter};
1212

1313
/// An owned BSON array value (akin to [`std::path::PathBuf`]), backed by a buffer of raw BSON
1414
/// bytes. This type can be used to construct owned array values, which can be used to append to
1515
/// [`RawDocumentBuf`] or as a field in a [`Deserialize`] struct.
1616
///
17-
/// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`] value that borrows from
18-
/// the original document without making any additional allocations.
17+
/// Iterating over a [`RawArrayBuf`] yields either an error or a [`RawBson`](crate::raw::RawBson)
18+
/// value that borrows from the original document without making any additional allocations.
1919
/// ```
2020
/// # use bson::raw::Error;
2121
/// use bson::raw::RawArrayBuf;
@@ -92,7 +92,7 @@ impl RawArrayBuf {
9292
/// assert!(iter.next().is_none());
9393
/// # Ok::<(), Error>(())
9494
/// ```
95-
pub fn push(&mut self, value: impl Into<RawBson>) {
95+
pub fn push(&mut self, value: impl BindRawBsonRef) {
9696
self.inner.append(self.len.to_string(), value);
9797
self.len += 1;
9898
}
@@ -148,7 +148,7 @@ impl<'a> From<&'a RawArrayBuf> for Cow<'a, RawArray> {
148148
}
149149
}
150150

151-
impl<T: Into<RawBson>> FromIterator<T> for RawArrayBuf {
151+
impl<T: BindRawBsonRef> FromIterator<T> for RawArrayBuf {
152152
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
153153
let mut array_buf = RawArrayBuf::new();
154154
for item in iter {

src/raw/document_buf.rs

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -189,43 +189,38 @@ impl RawDocumentBuf {
189189
///
190190
/// If the provided key contains an interior null byte, this method will panic.
191191
///
192+
/// Values can be any type that can be converted to either borrowed or owned raw bson data; see
193+
/// the documentation for [BindRawBsonRef] for more details.
192194
/// ```
193195
/// # use bson::raw::Error;
194-
/// use bson::{doc, raw::RawDocumentBuf};
196+
/// use bson::{doc, raw::{RawBsonRef, RawDocumentBuf}};
195197
///
196198
/// let mut doc = RawDocumentBuf::new();
199+
/// // `&str` and `i32` both convert to `RawBsonRef`
197200
/// doc.append("a string", "some string");
198201
/// doc.append("an integer", 12_i32);
199202
///
200203
/// let mut subdoc = RawDocumentBuf::new();
201204
/// subdoc.append("a key", true);
202-
/// doc.append("a document", subdoc);
205+
/// doc.append("a borrowed document", &subdoc);
206+
/// doc.append("an owned document", subdoc);
203207
///
204208
/// let expected = doc! {
205209
/// "a string": "some string",
206210
/// "an integer": 12_i32,
207-
/// "a document": { "a key": true },
211+
/// "a borrowed document": { "a key": true },
212+
/// "an owned document": { "a key": true },
208213
/// };
209214
///
210215
/// assert_eq!(doc.to_document()?, expected);
211216
/// # Ok::<(), Error>(())
212217
/// ```
213-
pub fn append(&mut self, key: impl AsRef<str>, value: impl Into<RawBson>) {
214-
let value = value.into();
215-
self.append_ref(key, value.as_raw_bson_ref())
216-
}
217-
218-
/// Append a key value pair to the end of the document without checking to see if
219-
/// the key already exists.
220-
///
221-
/// It is a user error to append the same key more than once to the same document, and it may
222-
/// result in errors when communicating with MongoDB.
223-
///
224-
/// If the provided key contains an interior null byte, this method will panic.
225-
pub fn append_ref<'a>(&mut self, key: impl AsRef<str>, value: impl Into<RawBsonRef<'a>>) {
226-
raw_writer::RawWriter::new(&mut self.data)
227-
.append(key.as_ref(), value.into())
228-
.expect("key should not contain interior null byte")
218+
pub fn append(&mut self, key: impl AsRef<str>, value: impl BindRawBsonRef) {
219+
value.bind(|value_ref| {
220+
raw_writer::RawWriter::new(&mut self.data)
221+
.append(key.as_ref(), value_ref)
222+
.expect("key should not contain interior null byte")
223+
})
229224
}
230225

231226
/// Convert this [`RawDocumentBuf`] to a [`Document`], returning an error
@@ -325,7 +320,7 @@ impl Borrow<RawDocument> for RawDocumentBuf {
325320
}
326321
}
327322

328-
impl<S: AsRef<str>, T: Into<RawBson>> FromIterator<(S, T)> for RawDocumentBuf {
323+
impl<S: AsRef<str>, T: BindRawBsonRef> FromIterator<(S, T)> for RawDocumentBuf {
329324
fn from_iter<I: IntoIterator<Item = (S, T)>>(iter: I) -> Self {
330325
let mut buf = RawDocumentBuf::new();
331326
for (k, v) in iter {
@@ -334,3 +329,68 @@ impl<S: AsRef<str>, T: Into<RawBson>> FromIterator<(S, T)> for RawDocumentBuf {
334329
buf
335330
}
336331
}
332+
333+
/// Types that can be consumed to produce raw bson references valid for a limited lifetime.
334+
/// Conceptually a union between `T: Into<RawBson>` and `T: Into<RawBsonRef>`; if your type
335+
/// implements `Into<RawBsonRef>` it will automatically implement this, but if it only
336+
/// implements `Into<RawBson>` it will need to manually define the trivial impl.
337+
pub trait BindRawBsonRef {
338+
fn bind<F, R>(self, f: F) -> R
339+
where
340+
F: for<'a> FnOnce(RawBsonRef<'a>) -> R;
341+
}
342+
343+
impl<'a, T: Into<RawBsonRef<'a>>> BindRawBsonRef for T {
344+
fn bind<F, R>(self, f: F) -> R
345+
where
346+
F: for<'b> FnOnce(RawBsonRef<'b>) -> R,
347+
{
348+
f(self.into())
349+
}
350+
}
351+
352+
impl BindRawBsonRef for RawBson {
353+
fn bind<F, R>(self, f: F) -> R
354+
where
355+
F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
356+
{
357+
f(self.as_raw_bson_ref())
358+
}
359+
}
360+
361+
impl BindRawBsonRef for &RawBson {
362+
fn bind<F, R>(self, f: F) -> R
363+
where
364+
F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
365+
{
366+
f(self.as_raw_bson_ref())
367+
}
368+
}
369+
370+
macro_rules! raw_bson_from_impls {
371+
($($t:ty),+$(,)?) => {
372+
$(
373+
impl BindRawBsonRef for $t {
374+
fn bind<F, R>(self, f: F) -> R
375+
where
376+
F: for<'a> FnOnce(RawBsonRef<'a>) -> R,
377+
{
378+
let tmp: RawBson = self.into();
379+
f(tmp.as_raw_bson_ref())
380+
}
381+
}
382+
)+
383+
};
384+
}
385+
386+
raw_bson_from_impls! {
387+
&crate::binary::Vector,
388+
crate::Binary,
389+
crate::DbPointer,
390+
super::RawArrayBuf,
391+
RawDocumentBuf,
392+
super::RawJavaScriptCodeWithScope,
393+
crate::Regex,
394+
String,
395+
crate::binary::Vector,
396+
}

src/raw/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ pub use self::{
140140
RawRegexRef,
141141
},
142142
document::RawDocument,
143-
document_buf::RawDocumentBuf,
143+
document_buf::{BindRawBsonRef, RawDocumentBuf},
144144
error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
145145
iter::{RawElement, RawIter},
146146
};

0 commit comments

Comments
 (0)