1use std::{
2 collections::HashSet,
3 convert::TryFrom,
4 io::{Read, Write},
5};
6
7use serde::Serialize;
8
9use crate::{
10 bson::{
11 oid::ObjectId,
12 rawdoc,
13 Bson,
14 Document,
15 RawArrayBuf,
16 RawBson,
17 RawBsonRef,
18 RawDocumentBuf,
19 },
20 checked::Checked,
21 error::{Error, ErrorKind, Result},
22 runtime::SyncLittleEndianRead,
23};
24
25#[allow(clippy::cast_possible_truncation)]
28pub(crate) fn get_int(val: &Bson) -> Option<i64> {
29 match *val {
30 Bson::Int32(i) => Some(i64::from(i)),
31 Bson::Int64(i) => Some(i),
32 Bson::Double(f) if (f - (f as i64 as f64)).abs() <= f64::EPSILON => Some(f as i64),
33 _ => None,
34 }
35}
36
37pub(crate) fn get_int_raw(val: RawBsonRef<'_>) -> Option<i64> {
40 match val {
41 RawBsonRef::Int32(i) => get_int(&Bson::Int32(i)),
42 RawBsonRef::Int64(i) => get_int(&Bson::Int64(i)),
43 RawBsonRef::Double(i) => get_int(&Bson::Double(i)),
44 _ => None,
45 }
46}
47
48#[allow(clippy::cast_possible_truncation)]
51pub(crate) fn get_u64(val: &Bson) -> Option<u64> {
52 match *val {
53 Bson::Int32(i) => u64::try_from(i).ok(),
54 Bson::Int64(i) => u64::try_from(i).ok(),
55 Bson::Double(f) if (f - (f as u64 as f64)).abs() <= f64::EPSILON => Some(f as u64),
56 _ => None,
57 }
58}
59
60pub(crate) fn to_bson_array(docs: &[Document]) -> Bson {
61 Bson::Array(docs.iter().map(|doc| Bson::Document(doc.clone())).collect())
62}
63
64pub(crate) fn to_raw_bson_array(docs: &[Document]) -> Result<RawBson> {
65 let mut array = RawArrayBuf::new();
66 for doc in docs {
67 array.push(RawDocumentBuf::from_document(doc)?);
68 }
69 Ok(RawBson::Array(array))
70}
71pub(crate) fn to_raw_bson_array_ser<T: Serialize>(values: &[T]) -> Result<RawBson> {
72 let mut array = RawArrayBuf::new();
73 for value in values {
74 array.push(bson::to_raw_document_buf(value)?);
75 }
76 Ok(RawBson::Array(array))
77}
78
79pub(crate) fn first_key(document: &Document) -> Option<&str> {
80 document.keys().next().map(String::as_str)
81}
82
83pub(crate) fn update_document_check(update: &Document) -> Result<()> {
84 match first_key(update) {
85 Some(key) => {
86 if !key.starts_with('$') {
87 Err(ErrorKind::InvalidArgument {
88 message: "update document must only contain update modifiers".to_string(),
89 }
90 .into())
91 } else {
92 Ok(())
93 }
94 }
95 None => Err(ErrorKind::InvalidArgument {
96 message: "update document must not be empty".to_string(),
97 }
98 .into()),
99 }
100}
101
102pub(crate) fn replacement_document_check(replacement: &Document) -> Result<()> {
103 if let Some(key) = first_key(replacement) {
104 if key.starts_with('$') {
105 return Err(ErrorKind::InvalidArgument {
106 message: "replacement document must not contain update modifiers".to_string(),
107 }
108 .into());
109 }
110 }
111 Ok(())
112}
113
114pub(crate) fn replacement_raw_document_check(replacement: &RawDocumentBuf) -> Result<()> {
115 if let Some((key, _)) = replacement.iter().next().transpose()? {
116 if key.starts_with('$') {
117 return Err(ErrorKind::InvalidArgument {
118 message: "replacement document must not contain update modifiers".to_string(),
119 }
120 .into());
121 };
122 }
123 Ok(())
124}
125
126pub(crate) fn array_entry_size_bytes(index: usize, doc_len: usize) -> Result<usize> {
128 (Checked::new(1) + num_decimal_digits(index) + 1 + doc_len).get()
134}
135
136pub(crate) fn vec_to_raw_array_buf(docs: Vec<RawDocumentBuf>) -> RawArrayBuf {
137 let mut array = RawArrayBuf::new();
138 for doc in docs {
139 array.push(doc);
140 }
141 array
142}
143
144fn num_decimal_digits(mut n: usize) -> usize {
147 let mut digits = 0;
148
149 loop {
150 n /= 10;
151 digits += 1;
152
153 if n == 0 {
154 return digits;
155 }
156 }
157}
158
159pub(crate) fn read_document_bytes<R: Read>(mut reader: R) -> Result<Vec<u8>> {
161 let length = Checked::new(reader.read_i32_sync()?);
162
163 let mut bytes = Vec::with_capacity(length.try_into()?);
164 bytes.write_all(&length.try_into::<u32>()?.to_le_bytes())?;
165
166 reader
167 .take((length - 4).try_into()?)
168 .read_to_end(&mut bytes)?;
169
170 Ok(bytes)
171}
172
173pub(crate) fn extend_raw_document_buf(
174 this: &mut RawDocumentBuf,
175 other: RawDocumentBuf,
176) -> Result<()> {
177 let mut keys: HashSet<String> = HashSet::new();
178 for elem in this.iter_elements() {
179 keys.insert(elem?.key().to_owned());
180 }
181 for result in other.iter() {
182 let (k, v) = result?;
183 if keys.contains(k) {
184 return Err(Error::internal(format!(
185 "duplicate raw document key {:?}",
186 k
187 )));
188 }
189 this.append(k, v.to_raw_bson());
190 }
191 Ok(())
192}
193
194pub(crate) fn append_ser(
195 this: &mut RawDocumentBuf,
196 key: impl AsRef<str>,
197 value: impl Serialize,
198) -> Result<()> {
199 #[derive(Serialize)]
200 struct Helper<T> {
201 value: T,
202 }
203 let raw_doc = bson::to_raw_document_buf(&Helper { value })?;
204 this.append_ref(
205 key,
206 raw_doc
207 .get("value")?
208 .ok_or_else(|| Error::internal("no value"))?,
209 );
210 Ok(())
211}
212
213pub(crate) fn get_or_prepend_id_field(doc: &mut RawDocumentBuf) -> Result<Bson> {
216 match doc.get("_id")? {
217 Some(id) => Ok(id.try_into()?),
218 None => {
219 let id = ObjectId::new();
220 let mut new_bytes = rawdoc! { "_id": id }.into_bytes();
221
222 new_bytes.pop();
225 new_bytes.extend(&doc.as_bytes()[4..]);
226
227 let new_length: i32 = Checked::new(new_bytes.len()).try_into()?;
228 new_bytes[0..4].copy_from_slice(&new_length.to_le_bytes());
229
230 *doc = RawDocumentBuf::from_bytes(new_bytes)?;
231
232 Ok(id.into())
233 }
234 }
235}
236
237#[cfg(test)]
238mod test {
239 use crate::bson_util::num_decimal_digits;
240
241 #[test]
242 fn num_digits() {
243 assert_eq!(num_decimal_digits(0), 1);
244 assert_eq!(num_decimal_digits(1), 1);
245 assert_eq!(num_decimal_digits(10), 2);
246 assert_eq!(num_decimal_digits(15), 2);
247 assert_eq!(num_decimal_digits(100), 3);
248 assert_eq!(num_decimal_digits(125), 3);
249 }
250}