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::RawIter,
};
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: [u8; 4] = 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_len(buf: &[u8]) -> Result<usize> {
if buf.len() < 4 {
return Err(Error::new_without_key(ErrorKind::MalformedValue {
message: 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::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(),
}));
}
Ok(length as usize + 4)
}
fn read_lenencode(buf: &[u8]) -> Result<&str> {
let end = read_len(buf)?;
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(),
})
})
}