Skip to content

Commit a44f669

Browse files
RUST-1366 Create serde_util module (mongodb#906)
1 parent 3ea196f commit a44f669

File tree

23 files changed

+380
-371
lines changed

23 files changed

+380
-371
lines changed

src/bson_util.rs

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use std::{
2+
convert::TryFrom,
3+
io::{Read, Write},
4+
};
5+
6+
use bson::RawBsonRef;
7+
8+
use crate::{
9+
bson::{Bson, Document},
10+
error::{ErrorKind, Result},
11+
runtime::SyncLittleEndianRead,
12+
};
13+
14+
/// Coerce numeric types into an `i64` if it would be lossless to do so. If this Bson is not numeric
15+
/// or the conversion would be lossy (e.g. 1.5 -> 1), this returns `None`.
16+
pub(crate) fn get_int(val: &Bson) -> Option<i64> {
17+
match *val {
18+
Bson::Int32(i) => Some(i64::from(i)),
19+
Bson::Int64(i) => Some(i),
20+
Bson::Double(f) if (f - (f as i64 as f64)).abs() <= f64::EPSILON => Some(f as i64),
21+
_ => None,
22+
}
23+
}
24+
25+
/// Coerce numeric types into an `i64` if it would be lossless to do so. If this Bson is not numeric
26+
/// or the conversion would be lossy (e.g. 1.5 -> 1), this returns `None`.
27+
pub(crate) fn get_int_raw(val: RawBsonRef<'_>) -> Option<i64> {
28+
match val {
29+
RawBsonRef::Int32(i) => get_int(&Bson::Int32(i)),
30+
RawBsonRef::Int64(i) => get_int(&Bson::Int64(i)),
31+
RawBsonRef::Double(i) => get_int(&Bson::Double(i)),
32+
_ => None,
33+
}
34+
}
35+
36+
/// Coerce numeric types into an `u64` if it would be lossless to do so. If this Bson is not numeric
37+
/// or the conversion would be lossy (e.g. 1.5 -> 1), this returns `None`.
38+
pub(crate) fn get_u64(val: &Bson) -> Option<u64> {
39+
match *val {
40+
Bson::Int32(i) => u64::try_from(i).ok(),
41+
Bson::Int64(i) => u64::try_from(i).ok(),
42+
Bson::Double(f) if (f - (f as u64 as f64)).abs() <= f64::EPSILON => Some(f as u64),
43+
_ => None,
44+
}
45+
}
46+
47+
pub(crate) fn to_bson_array(docs: &[Document]) -> Bson {
48+
Bson::Array(docs.iter().map(|doc| Bson::Document(doc.clone())).collect())
49+
}
50+
51+
#[cfg(test)]
52+
pub(crate) fn sort_document(document: &mut Document) {
53+
let temp = std::mem::take(document);
54+
55+
let mut elements: Vec<_> = temp.into_iter().collect();
56+
elements.sort_by(|e1, e2| e1.0.cmp(&e2.0));
57+
58+
document.extend(elements);
59+
}
60+
61+
pub(crate) fn first_key(document: &Document) -> Option<&str> {
62+
document.keys().next().map(String::as_str)
63+
}
64+
65+
pub(crate) fn replacement_document_check(replacement: &Document) -> Result<()> {
66+
match first_key(replacement) {
67+
Some(s) if !s.starts_with('$') => Ok(()),
68+
_ => Err(ErrorKind::InvalidArgument {
69+
message: "replace document must have first key not starting with '$".to_string(),
70+
}
71+
.into()),
72+
}
73+
}
74+
75+
pub(crate) fn update_document_check(update: &Document) -> Result<()> {
76+
match first_key(update) {
77+
Some(s) if s.starts_with('$') => Ok(()),
78+
_ => Err(ErrorKind::InvalidArgument {
79+
message: "update document must have first key starting with '$".to_string(),
80+
}
81+
.into()),
82+
}
83+
}
84+
85+
/// The size in bytes of the provided document's entry in a BSON array at the given index.
86+
pub(crate) fn array_entry_size_bytes(index: usize, doc_len: usize) -> u64 {
87+
// * type (1 byte)
88+
// * number of decimal digits in key
89+
// * null terminator for the key (1 byte)
90+
// * size of value
91+
92+
1 + num_decimal_digits(index) + 1 + doc_len as u64
93+
}
94+
95+
/// The number of digits in `n` in base 10.
96+
/// Useful for calculating the size of an array entry in BSON.
97+
fn num_decimal_digits(mut n: usize) -> u64 {
98+
let mut digits = 0;
99+
100+
loop {
101+
n /= 10;
102+
digits += 1;
103+
104+
if n == 0 {
105+
return digits;
106+
}
107+
}
108+
}
109+
110+
/// Read a document's raw BSON bytes from the provided reader.
111+
pub(crate) fn read_document_bytes<R: Read>(mut reader: R) -> Result<Vec<u8>> {
112+
let length = reader.read_i32_sync()?;
113+
114+
let mut bytes = Vec::with_capacity(length as usize);
115+
bytes.write_all(&length.to_le_bytes())?;
116+
117+
reader.take(length as u64 - 4).read_to_end(&mut bytes)?;
118+
119+
Ok(bytes)
120+
}
121+
122+
#[cfg(test)]
123+
mod test {
124+
use crate::bson_util::num_decimal_digits;
125+
126+
#[test]
127+
fn num_digits() {
128+
assert_eq!(num_decimal_digits(0), 1);
129+
assert_eq!(num_decimal_digits(1), 1);
130+
assert_eq!(num_decimal_digits(10), 2);
131+
assert_eq!(num_decimal_digits(15), 2);
132+
assert_eq!(num_decimal_digits(100), 3);
133+
assert_eq!(num_decimal_digits(125), 3);
134+
}
135+
}

src/bson_util/mod.rs

-262
This file was deleted.

0 commit comments

Comments
 (0)