Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provide lazy iterator implementation #449

Merged
merged 17 commits into from
Jan 18, 2024
7 changes: 5 additions & 2 deletions src/raw/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl<'a> IntoIterator for &'a RawArray {

fn into_iter(self) -> RawArrayIter<'a> {
RawArrayIter {
inner: self.doc.into_iter(),
inner: Iter::new(&self.doc),
}
}
}
Expand All @@ -275,7 +275,10 @@ impl<'a> Iterator for RawArrayIter<'a> {

fn next(&mut self) -> Option<Result<RawBsonRef<'a>>> {
match self.inner.next() {
Some(Ok((_, v))) => Some(Ok(v)),
Some(Ok(elem)) => match elem.value() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this just be Some(Ok(elem)) => Some(elem.value()) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup!

Ok(value) => Some(Ok(value)),
Err(e) => Some(Err(e)),
},
Some(Err(e)) => Some(Err(e)),
None => None,
}
Expand Down
31 changes: 24 additions & 7 deletions src/raw/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
use super::{
error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
i32_from_slice,
try_to_str,
Error,
Iter,
RawArray,
Expand Down Expand Up @@ -170,10 +171,10 @@ impl RawDocument {
/// # Ok::<(), Error>(())
/// ```
pub fn get(&self, key: impl AsRef<str>) -> Result<Option<RawBsonRef<'_>>> {
for result in self.into_iter() {
let (k, v) = result?;
if key.as_ref() == k {
return Ok(Some(v));
for elem in Iter::new(self) {
let elem = elem?;
if key.as_ref() == elem.key() {
return Ok(Some(elem.try_into()?));
}
}
Ok(None)
Expand Down Expand Up @@ -492,6 +493,22 @@ impl RawDocument {
pub fn is_empty(&self) -> bool {
self.as_bytes().len() == MIN_BSON_DOCUMENT_SIZE as usize
}

pub(crate) fn read_cstring_at(&self, start_at: usize) -> Result<&str> {
let buf = &self.as_bytes()[start_at..];

let mut splits = buf.splitn(2, |x| *x == 0);
let value = splits
.next()
.ok_or_else(|| Error::new_without_key(ErrorKind::new_malformed("no value")))?;
if splits.next().is_some() {
Ok(try_to_str(value)?)
} else {
Err(Error::new_without_key(ErrorKind::new_malformed(
"expected null terminator",
)))
}
}
}

impl<'de: 'a, 'a> Deserialize<'de> for &'a RawDocument {
Expand Down Expand Up @@ -577,10 +594,10 @@ impl TryFrom<&RawDocument> for crate::Document {
}

impl<'a> IntoIterator for &'a RawDocument {
type IntoIter = Iter<'a>;
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this is a breaking change. I think this can be solved by what you suggested in the conversation - keep the existing functionality named Iter and call the new one RawIter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alas, easy enough done

type Item = Result<(&'a str, RawBsonRef<'a>)>;

fn into_iter(self) -> Iter<'a> {
Iter::new(self)
fn into_iter(self) -> Box<dyn Iterator<Item = Result<(&'a str, RawBsonRef<'a>)>> + 'a> {
Box::new(Iter::new(self).into_eager())
}
}
30 changes: 25 additions & 5 deletions src/raw/document_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,28 @@ impl RawDocumentBuf {
/// There is no owning iterator for [`RawDocumentBuf`]. If you need ownership over
/// elements that might need to allocate, you must explicitly convert
/// them to owned types yourself.
pub fn iter(&self) -> Iter<'_> {
self.into_iter()
pub fn iter(&self) -> Box<dyn Iterator<Item = Result<(&'_ str, RawBsonRef<'_>)>> + '_> {
Iter::new(self).into_eager()
}

/// Gets an iterator over the elements in the [`RawDocumentBuf`],
/// which yields `Result<RawElement<'_>>` values. These hold a
/// reference to the underlying document but do not explicitly
/// resolve the values.
///
/// This iterator, which underpins the implementation of the
/// default iterator, produces `RawElement` objects, which
/// hold a view onto the document but do not parse out or
/// construct values until the `.value()` or `.try_into()` methods
/// are called.
///
/// # Note:
///
/// There is no owning iterator for [`RawDocumentBuf`]. If you
/// need ownership over elements that might need to allocate, you
/// must explicitly convert them to owned types yourself.
pub fn iter_elements(&self) -> Iter<'_> {
Iter::new(self)
}

/// Return the contained data as a `Vec<u8>`
Expand Down Expand Up @@ -369,11 +389,11 @@ impl TryFrom<&Document> for RawDocumentBuf {
}

impl<'a> IntoIterator for &'a RawDocumentBuf {
type IntoIter = Iter<'a>;
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
type Item = Result<(&'a str, RawBsonRef<'a>)>;

fn into_iter(self) -> Iter<'a> {
Iter::new(self)
fn into_iter(self) -> Box<dyn Iterator<Item = Self::Item> + 'a> {
Box::new(Iter::new(self).into_eager())
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/raw/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ pub enum ErrorKind {
Utf8EncodingError(Utf8Error),
}

impl ErrorKind {
pub(crate) fn new_malformed(e: impl ToString) -> Self {
ErrorKind::MalformedValue {
message: e.to_string(),
}
}
}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let p = self
Expand Down
Loading