1use std::{borrow::Cow, ops::Index};
2
3use bson::{Document, RawDocument};
4use bytes::BufMut;
5use indexmap::IndexMap;
6
7use crate::{MutableValue, put_raw_cstr, raw_cstr_len};
8
9#[derive(Default, Clone, Debug)]
10pub struct ParsedDocument<'a>(IndexMap<Cow<'a, str>, MutableValue<'a>>);
11
12impl<'a> ParsedDocument<'a> {
13 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn insert<V: Into<MutableValue<'static>>>(
18 &mut self,
19 key: impl Into<String>,
20 value: V,
21 ) -> Option<MutableValue<'_>> {
22 self.0.insert(Cow::from(key.into()), value.into())
23 }
24
25 pub fn remove(&mut self, key: impl AsRef<str>) -> Option<MutableValue<'a>> {
29 self.0.shift_remove(key.as_ref())
30 }
31
32 pub fn clear(&mut self) {
33 self.0.clear()
34 }
35
36 pub fn contains_key(&self, key: impl AsRef<str>) -> bool {
37 self.0.contains_key(key.as_ref())
38 }
39
40 pub fn get(&self, key: impl AsRef<str>) -> Option<&MutableValue<'a>> {
41 self.0.get(key.as_ref())
42 }
43
44 pub fn get_mut(&mut self, key: impl AsRef<str>) -> Option<&mut MutableValue<'a>> {
45 self.0.get_mut(key.as_ref())
46 }
47
48 pub fn iter(&self) -> impl Iterator<Item = (&str, &MutableValue<'a>)> {
49 self.0.iter().map(|(k, v)| (k.as_ref(), v))
50 }
51
52 pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut MutableValue<'a>)> {
53 self.0.iter_mut().map(|(k, v)| (k.as_ref(), v))
54 }
55
56 pub fn len(&self) -> usize {
57 self.0.len()
58 }
59
60 pub fn is_empty(&self) -> bool {
61 self.0.is_empty()
62 }
63
64 pub(super) fn raw_len(&self) -> usize {
65 self.0
66 .iter()
67 .map(|(k, v)| 1 + raw_cstr_len(k.as_ref()) + v.raw_len())
69 .sum::<usize>()
70 + 4usize + 1usize
72 }
73
74 pub(super) fn put(&self, buf: &mut impl BufMut) -> Result<(), bson::ser::Error> {
75 buf.put_i32_le(
76 self.raw_len()
77 .try_into()
78 .expect("message len checked before put"),
79 );
80 for (k, v) in self.0.iter() {
81 buf.put_u8(v.element_type() as u8);
82 put_raw_cstr(k.as_ref(), buf)?;
83 v.put(buf)?;
84 }
85 buf.put_u8(0);
86 Ok(())
87 }
88
89 }
94
95impl<'a> TryFrom<&'a RawDocument> for ParsedDocument<'a> {
96 type Error = bson::raw::Error;
97
98 fn try_from(value: &'a RawDocument) -> Result<Self, Self::Error> {
99 let mut fields = IndexMap::new();
100 for e in value.iter() {
101 let (k, v) = e?;
102 fields.insert(k.into(), v.into());
103 }
104 Ok(Self(fields))
105 }
106}
107
108impl From<Document> for ParsedDocument<'_> {
109 fn from(value: Document) -> Self {
110 Self(
111 value
112 .into_iter()
113 .map(|(k, v)| (k.into(), v.into()))
114 .collect(),
115 )
116 }
117}
118
119impl<'a, S: AsRef<str>> Index<S> for ParsedDocument<'a> {
120 type Output = MutableValue<'a>;
121
122 fn index(&self, index: S) -> &Self::Output {
123 &self.0[index.as_ref()]
124 }
125}
126
127#[cfg(test)]
128mod test {
129 use bson::{
130 Binary, Bson, DateTime, Decimal128, Document, JavaScriptCodeWithScope, RawDocumentBuf,
131 Regex, Timestamp, bson, doc, oid::ObjectId, rawdoc, to_raw_document_buf,
132 };
133
134 use crate::MutableValue;
135
136 use super::ParsedDocument;
137
138 fn doc_to_vec(doc: &ParsedDocument<'_>) -> Vec<u8> {
139 let mut out = vec![];
140 doc.put(&mut out).unwrap();
141 out
142 }
143
144 fn doc_all_types_owned() -> Document {
145 let mut doc = Document::new();
146 doc.insert("a", 1.0f64);
147 doc.insert("b", "str");
148 doc.insert("c", doc! { "text": "the quick brown fox" });
149 doc.insert("d", bson!([1, "value"]));
150 doc.insert(
151 "e",
152 Binary {
153 subtype: bson::spec::BinarySubtype::Generic,
154 bytes: vec![1u8, 2, 3],
155 },
156 );
157 doc.insert("f", Bson::Undefined);
158 doc.insert("g", ObjectId::from_bytes([0xae; 12]));
159 doc.insert("h", true);
160 doc.insert("i", DateTime::from_millis(1234567890));
161 doc.insert("j", Bson::Null);
162 doc.insert(
163 "k",
164 Regex {
165 pattern: "foo.*".into(),
166 options: "i".into(),
167 },
168 );
169 doc.insert("m", Bson::JavaScriptCode("some code".into()));
170 doc.insert("n", Bson::Symbol("symbol".into()));
171 doc.insert(
172 "o",
173 JavaScriptCodeWithScope {
174 code: "more code".into(),
175 scope: doc! {"text": "jumped over the lazy dog"},
176 },
177 );
178 doc.insert("p", 7i32);
179 doc.insert(
180 "q",
181 Timestamp {
182 time: 1234567890,
183 increment: 2,
184 },
185 );
186 doc.insert("r", 11i64);
187 doc.insert("s", Decimal128::from_bytes([0xaf; 16]));
188 doc.insert("t", Bson::MinKey);
189 doc.insert("u", Bson::MaxKey);
190 doc
191 }
192
193 fn doc_all_types_unowned() -> RawDocumentBuf {
194 to_raw_document_buf(&doc_all_types_owned()).unwrap()
195 }
196
197 #[test]
198 fn empty() {
199 let doc = ParsedDocument::new();
200 assert_eq!(doc.len(), 0);
201 assert!(doc.is_empty());
202 assert!(doc.iter().next().is_none());
203 assert_eq!(doc.raw_len(), 5);
204 assert_eq!(doc_to_vec(&doc), vec![5, 0, 0, 0, 0]);
205 }
206
207 #[test]
208 fn all_types_owned() {
209 let doc = ParsedDocument::from(doc_all_types_owned());
210 assert_eq!(doc_to_vec(&doc), doc_all_types_unowned().as_bytes());
211 }
212
213 #[test]
214 fn all_types_unowned() {
215 let raw_doc = doc_all_types_unowned();
216 let doc = ParsedDocument::try_from(raw_doc.as_ref()).unwrap();
217 assert_eq!(doc_to_vec(&doc), doc_all_types_unowned().as_bytes());
218 }
219
220 #[test]
221 fn contains_key() {
222 let doc = ParsedDocument::from(doc_all_types_owned());
223 assert!(doc.contains_key("e"));
224 assert!(!doc.contains_key("z"));
225 }
226
227 #[test]
228 fn get() {
229 let doc = ParsedDocument::from(doc_all_types_owned());
230 assert_eq!(doc.get("p").and_then(MutableValue::as_i32).unwrap(), 7);
231 assert!(doc.get("z").is_none());
232 }
233
234 #[test]
235 fn index() {
236 let doc = ParsedDocument::from(doc_all_types_owned());
237 assert_eq!(doc["p"].as_i32().unwrap(), 7);
238 assert!(doc.get("z").is_none());
239 }
240
241 #[test]
242 #[should_panic]
243 fn index_invalid() {
244 let doc = ParsedDocument::from(doc_all_types_owned());
245 let _ = doc["z"];
246 }
247
248 #[test]
249 fn insert_and_replace() {
250 let mut doc = ParsedDocument::new();
251 assert!(doc.insert("foo", 5).is_none());
252 assert!(doc.insert("bar", "bat").is_none());
253 assert_eq!(
254 doc_to_vec(&doc),
255 rawdoc! { "foo": 5, "bar": "bat" }.as_bytes()
256 );
257
258 assert!(doc.insert("foo", 16384).is_some());
259 assert_eq!(
260 doc_to_vec(&doc),
261 rawdoc! { "foo": 16384, "bar": "bat" }.as_bytes()
262 );
263 }
264
265 #[test]
266 fn remove() {
267 let mut doc = ParsedDocument::new();
268 assert!(doc.insert("foo", 5).is_none());
269 assert!(doc.insert("bar", "bat").is_none());
270 assert_eq!(
271 doc_to_vec(&doc),
272 rawdoc! { "foo": 5, "bar": "bat" }.as_bytes()
273 );
274
275 assert!(doc.remove("foo").is_some());
276 assert_eq!(doc_to_vec(&doc), rawdoc! { "bar": "bat" }.as_bytes());
277
278 assert!(doc.remove("foo").is_none());
279 }
280
281 #[test]
282 fn get_mut() {
283 let mut doc = ParsedDocument::new();
284 assert!(doc.insert("foo", 5).is_none());
285 assert!(doc.get_mut("bar").is_none());
286
287 let v = doc.get_mut("foo").expect("foo is present");
288 if let MutableValue::Int32(i) = v {
289 assert_eq!(*i, 5);
290 } else {
291 panic!("not an int32");
292 }
293
294 *v = "bar".into();
295 assert_eq!(doc_to_vec(&doc), rawdoc! { "foo": "bar" }.as_bytes());
296 }
297
298 #[test]
299 fn clear() {
300 let mut doc = ParsedDocument::from(doc_all_types_owned());
301 assert_eq!(doc_to_vec(&doc), doc_all_types_unowned().as_bytes());
302
303 doc.clear();
304 assert_eq!(doc_to_vec(&doc), vec![5, 0, 0, 0, 0]);
305 }
306
307 #[test]
308 fn mutate_unowned() {
309 let raw_doc = rawdoc! { "foo": "bar", "bat": 5 };
310 let mut doc = ParsedDocument::try_from(raw_doc.as_ref()).unwrap();
311 assert!(doc.insert("bat", true).is_some());
312 assert!(doc.insert("quux", 7).is_none());
313 assert_eq!(
314 doc_to_vec(&doc),
315 rawdoc! { "foo": "bar", "bat": true, "quux": 7 }.as_bytes()
316 );
317 }
318
319 #[test]
320 fn mutate_unowned_embedded_doc() {
321 let raw_doc = rawdoc! { "foo": 5, "bar": { "id": 0, "score": 1.1 }};
322 let mut doc = ParsedDocument::try_from(raw_doc.as_ref()).unwrap();
323 let emb_doc = doc
324 .get_mut("bar")
325 .and_then(MutableValue::as_doc_mut)
326 .unwrap()
327 .to_parsed()
328 .unwrap();
329 assert!(emb_doc.insert("score", 2.1).is_some());
330 assert!(emb_doc.insert("price", 7.17).is_none());
331 assert_eq!(
332 doc_to_vec(&doc),
333 rawdoc! { "foo": 5, "bar": { "id": 0, "score": 2.1, "price": 7.17 }}.as_bytes()
334 );
335 }
336
337 #[test]
338 fn mutate_embedded_array() {
339 let raw_doc = rawdoc! { "foo": 5, "vec": [0, "foo", 2, 3]};
340 let mut doc = ParsedDocument::try_from(raw_doc.as_ref()).unwrap();
341 let emb_array = doc
342 .get_mut("vec")
343 .and_then(MutableValue::as_array_mut)
344 .unwrap()
345 .to_parsed()
346 .unwrap();
347 emb_array[2] = "bar".into();
348 emb_array.push(4.into());
349 assert_eq!(
350 doc_to_vec(&doc),
351 rawdoc! { "foo": 5, "vec": [0, "foo", "bar", 3, 4]}.as_bytes()
352 );
353 }
354}