mod array;
mod array_buf;
mod bson;
mod bson_ref;
mod cstr;
pub(crate) mod doc_writer;
mod document;
mod document_buf;
mod iter;
#[cfg(feature = "serde")]
pub(crate) mod serde;
#[cfg(test)]
mod test;
use std::{
convert::{TryFrom, TryInto},
io::Read,
};
use crate::error::{Error, ErrorKind, Result};
pub use self::{
array::{RawArray, RawArrayIter},
array_buf::RawArrayBuf,
bson::{RawBson, RawJavaScriptCodeWithScope},
bson_ref::{
RawBinaryRef,
RawBsonRef,
RawDbPointerRef,
RawJavaScriptCodeWithScopeRef,
RawRegexRef,
},
cstr::{assert_valid_cstr, cstr, validate_cstr, CStr, CString, IsValidCStr},
document::RawDocument,
document_buf::{BindRawBsonRef, BindValue, RawDocumentBuf},
iter::{RawElement, RawIter},
};
pub(crate) const MIN_BSON_STRING_SIZE: i32 = 4 + 1; pub(crate) const MIN_BSON_DOCUMENT_SIZE: i32 = 4 + 1; pub(crate) const MIN_CODE_WITH_SCOPE_SIZE: i32 = 4 + MIN_BSON_STRING_SIZE + MIN_BSON_DOCUMENT_SIZE;
#[cfg(feature = "serde")]
pub(crate) use self::iter::{Utf8LossyBson, Utf8LossyJavaScriptCodeWithScope};
#[cfg(feature = "serde")]
pub(crate) const RAW_DOCUMENT_NEWTYPE: &str = "$__private__bson_RawDocument";
#[cfg(feature = "serde")]
pub(crate) const RAW_ARRAY_NEWTYPE: &str = "$__private__bson_RawArray";
#[cfg(feature = "serde")]
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_bytes(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_bytes(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_bytes(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_bytes(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_bytes(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_bytes(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_bytes(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_bytes(format!(
"expected buffer to contain at least {} bytes, but it only has {}",
end,
buf.len()
)));
}
if buf[end - 1] != 0 {
return Err(Error::malformed_bytes(
"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> {
simdutf8::basic::from_utf8(data).map_err(|_| ErrorKind::Utf8Encoding {}.into())
}
fn usize_try_from_i32(i: i32) -> Result<usize> {
usize::try_from(i).map_err(Error::malformed_bytes)
}
fn checked_add(lhs: usize, rhs: usize) -> Result<usize> {
lhs.checked_add(rhs)
.ok_or_else(|| Error::malformed_bytes("attempted to add with overflow"))
}
pub(crate) fn reader_to_vec<R: Read>(mut reader: R) -> Result<Vec<u8>> {
let mut buf = [0; 4];
reader.read_exact(&mut buf)?;
let length = i32::from_le_bytes(buf);
if length < MIN_BSON_DOCUMENT_SIZE {
return Err(Error::malformed_bytes("document size too small"));
}
let mut bytes = Vec::with_capacity(length as usize);
bytes.extend(buf);
reader.take(length as u64 - 4).read_to_end(&mut bytes)?;
Ok(bytes)
}
pub(crate) fn write_string(buf: &mut Vec<u8>, s: &str) {
buf.extend(&(s.len() as i32 + 1).to_le_bytes());
buf.extend(s.as_bytes());
buf.push(0);
}