mod array;
mod array_buf;
mod bson;
mod bson_ref;
mod document;
mod document_buf;
mod error;
mod iter;
pub(crate) mod serde;
#[cfg(test)]
mod test;
use std::convert::{TryFrom, TryInto};
use crate::de::MIN_BSON_STRING_SIZE;
pub use self::{
array::{RawArray, RawArrayIter},
array_buf::RawArrayBuf,
bson::{RawBson, RawJavaScriptCodeWithScope},
bson_ref::{
RawBinaryRef,
RawBsonRef,
RawDbPointerRef,
RawJavaScriptCodeWithScopeRef,
RawRegexRef,
},
document::RawDocument,
document_buf::RawDocumentBuf,
error::{Error, ErrorKind, Result, ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
iter::{RawElement, RawIter},
};
pub(crate) use self::iter::{Utf8LossyBson, Utf8LossyJavaScriptCodeWithScope};
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::malformed(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: [u8; 4] = val
.get(0..4)
.and_then(|s| s.try_into().ok())
.ok_or_else(|| {
Error::malformed(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::malformed(format!(
"expected 8 bytes to read i64, instead got {}",
val.len()
))
})?;
Ok(i64::from_le_bytes(arr))
}
fn u8_from_slice(val: &[u8]) -> Result<u8> {
let arr = val
.get(0..1)
.and_then(|s| s.try_into().ok())
.ok_or_else(|| {
Error::malformed(format!(
"expected 1 byte to read u8, instead got {}",
val.len()
))
})?;
Ok(u8::from_le_bytes(arr))
}
pub(crate) fn bool_from_slice(val: &[u8]) -> Result<bool> {
let val = u8_from_slice(val)?;
if val > 1 {
return Err(Error::malformed(format!(
"boolean must be stored as 0 or 1, got {}",
val
)));
}
Ok(val != 0)
}
fn read_len(buf: &[u8]) -> Result<usize> {
if buf.len() < 4 {
return Err(Error::malformed(format!(
"expected buffer with string to contain at least 4 bytes, but it only has {}",
buf.len()
)));
}
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::malformed(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::malformed(format!(
"expected buffer to contain at least {} bytes, but it only has {}",
end,
buf.len()
)));
}
if buf[end - 1] != 0 {
return Err(Error::malformed("expected string to be null-terminated"));
}
Ok(length as usize + 4)
}
fn read_lenencode_bytes(buf: &[u8]) -> Result<&[u8]> {
let end = read_len(buf)?;
Ok(&buf[4..(end - 1)])
}
fn read_lenencode(buf: &[u8]) -> Result<&str> {
try_to_str(read_lenencode_bytes(buf)?)
}
fn try_to_str(data: &[u8]) -> Result<&str> {
std::str::from_utf8(data).map_err(|e| Error::new(ErrorKind::Utf8EncodingError(e)))
}
fn usize_try_from_i32(i: i32) -> Result<usize> {
usize::try_from(i).map_err(Error::malformed)
}
fn checked_add(lhs: usize, rhs: usize) -> Result<usize> {
lhs.checked_add(rhs)
.ok_or_else(|| Error::malformed("attempted to add with overflow"))
}