mod array;
mod bson;
mod document;
mod document_buf;
mod error;
mod iter;
#[cfg(test)]
mod test;
use std::convert::{TryFrom, TryInto};
use crate::de::MIN_BSON_STRING_SIZE;
pub use self::{
array::{RawArray, RawArrayIter},
bson::{RawBinary, RawBson, RawDbPointer, RawJavaScriptCodeWithScope, RawRegex},
document::RawDocument,
document_buf::RawDocumentBuf,
error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
iter::Iter,
};
pub(crate) use self::bson::RawBsonVisitor;
pub(crate) const RAW_DOCUMENT_NEWTYPE: &str = "$__private__bson_RawDocument";
pub(crate) const RAW_ARRAY_NEWTYPE: &str = "$__private__bson_RawArray";
pub(crate) const RAW_BSON_NEWTYPE: &str = "$__private__bson_RawBson";
fn f64_from_slice(val: &[u8]) -> Result<f64> {
let arr = val
.get(0..8)
.and_then(|s| s.try_into().ok())
.ok_or_else(|| {
Error::new_without_key(ErrorKind::MalformedValue {
message: format!("expected 8 bytes to read double, instead got {}", val.len()),
})
})?;
Ok(f64::from_le_bytes(arr))
}
fn i32_from_slice(val: &[u8]) -> Result<i32> {
let arr = val
.get(0..4)
.and_then(|s| s.try_into().ok())
.ok_or_else(|| {
Error::new_without_key(ErrorKind::MalformedValue {
message: format!("expected 4 bytes to read i32, instead got {}", val.len()),
})
})?;
Ok(i32::from_le_bytes(arr))
}
fn i64_from_slice(val: &[u8]) -> Result<i64> {
let arr = val
.get(0..8)
.and_then(|s| s.try_into().ok())
.ok_or_else(|| {
Error::new_without_key(ErrorKind::MalformedValue {
message: format!("expected 8 bytes to read i64, instead got {}", val.len()),
})
})?;
Ok(i64::from_le_bytes(arr))
}
fn read_nullterminated(buf: &[u8]) -> Result<&str> {
let mut splits = buf.splitn(2, |x| *x == 0);
let value = splits.next().ok_or_else(|| {
Error::new_without_key(ErrorKind::MalformedValue {
message: "no value".into(),
})
})?;
if splits.next().is_some() {
Ok(try_to_str(value)?)
} else {
Err(Error::new_without_key(ErrorKind::MalformedValue {
message: "expected null terminator".into(),
}))
}
}
fn read_lenencoded(buf: &[u8]) -> Result<&str> {
let length = i32_from_slice(&buf[..4])?;
let end = checked_add(usize_try_from_i32(length)?, 4)?;
if end < MIN_BSON_STRING_SIZE as usize {
return Err(Error::new_without_key(ErrorKind::MalformedValue {
message: format!(
"BSON length encoded string needs to be at least {} bytes, instead got {}",
MIN_BSON_STRING_SIZE, end
),
}));
}
if buf.len() < end {
return Err(Error::new_without_key(ErrorKind::MalformedValue {
message: format!(
"expected buffer to contain at least {} bytes, but it only has {}",
end,
buf.len()
),
}));
}
if buf[end - 1] != 0 {
return Err(Error::new_without_key(ErrorKind::MalformedValue {
message: "expected string to be null-terminated".to_string(),
}));
}
try_to_str(&buf[4..(end - 1)])
}
fn try_to_str(data: &[u8]) -> Result<&str> {
std::str::from_utf8(data).map_err(|e| Error::new_without_key(ErrorKind::Utf8EncodingError(e)))
}
fn usize_try_from_i32(i: i32) -> Result<usize> {
usize::try_from(i).map_err(|e| {
Error::new_without_key(ErrorKind::MalformedValue {
message: e.to_string(),
})
})
}
fn checked_add(lhs: usize, rhs: usize) -> Result<usize> {
lhs.checked_add(rhs).ok_or_else(|| {
Error::new_without_key(ErrorKind::MalformedValue {
message: "attempted to add with overflow".to_string(),
})
})
}