/src/bson-rust/src/raw/array.rs
Line | Count | Source |
1 | | use std::{borrow::Cow, convert::TryFrom}; |
2 | | |
3 | | use super::{ |
4 | | Error as RawError, |
5 | | RawBinaryRef, |
6 | | RawBsonRef, |
7 | | RawDocument, |
8 | | RawIter, |
9 | | RawRegexRef, |
10 | | Result as RawResult, |
11 | | }; |
12 | | use crate::{ |
13 | | error::{Error, Result}, |
14 | | oid::ObjectId, |
15 | | spec::ElementType, |
16 | | Bson, |
17 | | DateTime, |
18 | | RawArrayBuf, |
19 | | Timestamp, |
20 | | }; |
21 | | |
22 | | /// A slice of a BSON document containing a BSON array value (akin to [`std::str`]). This can be |
23 | | /// retrieved from a [`RawDocument`] via [`RawDocument::get`]. |
24 | | /// |
25 | | /// This is an _unsized_ type, meaning that it must always be used behind a pointer like `&`. |
26 | | /// |
27 | | /// Accessing elements within a [`RawArray`] is similar to element access in [`crate::Document`], |
28 | | /// but because the contents are parsed during iteration instead of at creation time, format errors |
29 | | /// can happen at any time during use. |
30 | | /// |
31 | | /// Iterating over a [`RawArray`] yields either an error or a value that borrows from the |
32 | | /// original document without making any additional allocations. |
33 | | /// |
34 | | /// ``` |
35 | | /// use bson::{doc, raw::RawDocument}; |
36 | | /// |
37 | | /// let doc = doc! { |
38 | | /// "x": [1, true, "two", 5.5] |
39 | | /// }; |
40 | | /// let bytes = bson::serialize_to_vec(&doc)?; |
41 | | /// |
42 | | /// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?; |
43 | | /// let rawarray = rawdoc.get_array("x")?; |
44 | | /// |
45 | | /// for v in rawarray { |
46 | | /// println!("{:?}", v?); |
47 | | /// } |
48 | | /// # Ok::<(), Box<dyn std::error::Error>>(()) |
49 | | /// ``` |
50 | | /// |
51 | | /// Individual elements can be accessed using [`RawArray::get`] or any of |
52 | | /// the type-specific getters, such as [`RawArray::get_object_id`] or |
53 | | /// [`RawArray::get_str`]. Note that accessing elements is an O(N) operation, as it |
54 | | /// requires iterating through the array from the beginning to find the requested index. |
55 | | /// |
56 | | /// ``` |
57 | | /// use bson::{doc, raw::RawDocument}; |
58 | | /// |
59 | | /// let doc = doc! { |
60 | | /// "x": [1, true, "two", 5.5] |
61 | | /// }; |
62 | | /// let bytes = doc.to_vec()?; |
63 | | /// |
64 | | /// let rawdoc = RawDocument::from_bytes(bytes.as_slice())?; |
65 | | /// let rawarray = rawdoc.get_array("x")?; |
66 | | /// |
67 | | /// assert_eq!(rawarray.get_bool(1)?, true); |
68 | | /// # Ok::<(), Box<dyn std::error::Error>>(()) |
69 | | /// ``` |
70 | | #[derive(PartialEq)] |
71 | | #[repr(transparent)] |
72 | | pub struct RawArray { |
73 | | pub(crate) doc: RawDocument, |
74 | | } |
75 | | |
76 | | impl RawArray { |
77 | 280k | pub(crate) fn from_doc(doc: &RawDocument) -> &RawArray { |
78 | | // SAFETY: |
79 | | // |
80 | | // Dereferencing a raw pointer requires unsafe due to the potential that the pointer is |
81 | | // null, dangling, or misaligned. We know the pointer is not null or dangling due to the |
82 | | // fact that it's created by a safe reference. Converting &RawDocument to *const |
83 | | // RawDocument will be properly aligned due to them being references to the same type, |
84 | | // and converting *const RawDocument to *const RawArray is aligned due to the fact that |
85 | | // the only field in a RawArray is a RawDocument, meaning the structs are represented |
86 | | // identically at the byte level. |
87 | 280k | unsafe { &*(doc as *const RawDocument as *const RawArray) } |
88 | 280k | } |
89 | | |
90 | | #[cfg(feature = "serde")] |
91 | 17.1k | pub(crate) fn as_doc(&self) -> &RawDocument { |
92 | 17.1k | &self.doc |
93 | 17.1k | } |
94 | | |
95 | | /// Gets a reference to the value at the given index. |
96 | 0 | pub fn get(&self, index: usize) -> RawResult<Option<RawBsonRef<'_>>> { |
97 | 0 | self.into_iter().nth(index).transpose() |
98 | 0 | } |
99 | | |
100 | 0 | fn get_with<'a, T>( |
101 | 0 | &'a self, |
102 | 0 | index: usize, |
103 | 0 | expected_type: ElementType, |
104 | 0 | f: impl FnOnce(RawBsonRef<'a>) -> Option<T>, |
105 | 0 | ) -> Result<T> { |
106 | 0 | let bson = self |
107 | 0 | .get(index) |
108 | 0 | .map_err(|e| Error::value_access_invalid_bson(format!("{:?}", e)))?Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::raw::bson_ref::RawRegexRef, <bson::raw::bson_ref::RawBsonRef>::as_regex>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::raw::bson_ref::RawBinaryRef, <bson::raw::bson_ref::RawBsonRef>::as_binary>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::oid::ObjectId, <bson::raw::bson_ref::RawBsonRef>::as_object_id>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::bson::Timestamp, <bson::raw::bson_ref::RawBsonRef>::as_timestamp>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::datetime::DateTime, <bson::raw::bson_ref::RawBsonRef>::as_datetime>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&bson::raw::array::RawArray, <bson::raw::bson_ref::RawBsonRef>::as_array>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&bson::raw::document::RawDocument, <bson::raw::bson_ref::RawBsonRef>::as_document>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&str, <bson::raw::bson_ref::RawBsonRef>::as_str>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bool, <bson::raw::bson_ref::RawBsonRef>::as_bool>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<f64, <bson::raw::bson_ref::RawBsonRef>::as_f64>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<i32, <bson::raw::bson_ref::RawBsonRef>::as_i32>::{closure#0}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<i64, <bson::raw::bson_ref::RawBsonRef>::as_i64>::{closure#0} |
109 | 0 | .ok_or_else(Error::value_access_not_present) |
110 | 0 | .map_err(|e| e.with_index(index))?; Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::raw::bson_ref::RawRegexRef, <bson::raw::bson_ref::RawBsonRef>::as_regex>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::raw::bson_ref::RawBinaryRef, <bson::raw::bson_ref::RawBsonRef>::as_binary>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::oid::ObjectId, <bson::raw::bson_ref::RawBsonRef>::as_object_id>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::bson::Timestamp, <bson::raw::bson_ref::RawBsonRef>::as_timestamp>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::datetime::DateTime, <bson::raw::bson_ref::RawBsonRef>::as_datetime>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&bson::raw::array::RawArray, <bson::raw::bson_ref::RawBsonRef>::as_array>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&bson::raw::document::RawDocument, <bson::raw::bson_ref::RawBsonRef>::as_document>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&str, <bson::raw::bson_ref::RawBsonRef>::as_str>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bool, <bson::raw::bson_ref::RawBsonRef>::as_bool>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<f64, <bson::raw::bson_ref::RawBsonRef>::as_f64>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<i32, <bson::raw::bson_ref::RawBsonRef>::as_i32>::{closure#1}Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<i64, <bson::raw::bson_ref::RawBsonRef>::as_i64>::{closure#1} |
111 | 0 | match f(bson) { |
112 | 0 | Some(t) => Ok(t), |
113 | 0 | None => Err( |
114 | 0 | Error::value_access_unexpected_type(bson.element_type(), expected_type) |
115 | 0 | .with_index(index), |
116 | 0 | ), |
117 | | } |
118 | 0 | } Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::raw::bson_ref::RawRegexRef, <bson::raw::bson_ref::RawBsonRef>::as_regex> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::raw::bson_ref::RawBinaryRef, <bson::raw::bson_ref::RawBsonRef>::as_binary> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::oid::ObjectId, <bson::raw::bson_ref::RawBsonRef>::as_object_id> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::bson::Timestamp, <bson::raw::bson_ref::RawBsonRef>::as_timestamp> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bson::datetime::DateTime, <bson::raw::bson_ref::RawBsonRef>::as_datetime> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&bson::raw::array::RawArray, <bson::raw::bson_ref::RawBsonRef>::as_array> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&bson::raw::document::RawDocument, <bson::raw::bson_ref::RawBsonRef>::as_document> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<&str, <bson::raw::bson_ref::RawBsonRef>::as_str> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<bool, <bson::raw::bson_ref::RawBsonRef>::as_bool> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<f64, <bson::raw::bson_ref::RawBsonRef>::as_f64> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<i32, <bson::raw::bson_ref::RawBsonRef>::as_i32> Unexecuted instantiation: <bson::raw::array::RawArray>::get_with::<i64, <bson::raw::bson_ref::RawBsonRef>::as_i64> |
119 | | |
120 | | /// Gets the BSON double at the given index or returns an error if the value at that index isn't |
121 | | /// a double. |
122 | 0 | pub fn get_f64(&self, index: usize) -> Result<f64> { |
123 | 0 | self.get_with(index, ElementType::Double, RawBsonRef::as_f64) |
124 | 0 | } |
125 | | |
126 | | /// Gets a reference to the string at the given index or returns an error if the |
127 | | /// value at that index isn't a string. |
128 | 0 | pub fn get_str(&self, index: usize) -> Result<&str> { |
129 | 0 | self.get_with(index, ElementType::String, RawBsonRef::as_str) |
130 | 0 | } |
131 | | |
132 | | /// Gets a reference to the document at the given index or returns an error if the |
133 | | /// value at that index isn't a document. |
134 | 0 | pub fn get_document(&self, index: usize) -> Result<&RawDocument> { |
135 | 0 | self.get_with( |
136 | 0 | index, |
137 | 0 | ElementType::EmbeddedDocument, |
138 | | RawBsonRef::as_document, |
139 | | ) |
140 | 0 | } |
141 | | |
142 | | /// Gets a reference to the array at the given index or returns an error if the |
143 | | /// value at that index isn't a array. |
144 | 0 | pub fn get_array(&self, index: usize) -> Result<&RawArray> { |
145 | 0 | self.get_with(index, ElementType::Array, RawBsonRef::as_array) |
146 | 0 | } |
147 | | |
148 | | /// Gets a reference to the BSON binary value at the given index or returns an error if the |
149 | | /// value at that index isn't a binary. |
150 | 0 | pub fn get_binary(&self, index: usize) -> Result<RawBinaryRef<'_>> { |
151 | 0 | self.get_with(index, ElementType::Binary, RawBsonRef::as_binary) |
152 | 0 | } |
153 | | |
154 | | /// Gets the ObjectId at the given index or returns an error if the value at that index isn't an |
155 | | /// ObjectId. |
156 | 0 | pub fn get_object_id(&self, index: usize) -> Result<ObjectId> { |
157 | 0 | self.get_with(index, ElementType::ObjectId, RawBsonRef::as_object_id) |
158 | 0 | } |
159 | | |
160 | | /// Gets the boolean at the given index or returns an error if the value at that index isn't a |
161 | | /// boolean. |
162 | 0 | pub fn get_bool(&self, index: usize) -> Result<bool> { |
163 | 0 | self.get_with(index, ElementType::Boolean, RawBsonRef::as_bool) |
164 | 0 | } |
165 | | |
166 | | /// Gets the DateTime at the given index or returns an error if the value at that index isn't a |
167 | | /// DateTime. |
168 | 0 | pub fn get_datetime(&self, index: usize) -> Result<DateTime> { |
169 | 0 | self.get_with(index, ElementType::DateTime, RawBsonRef::as_datetime) |
170 | 0 | } |
171 | | |
172 | | /// Gets a reference to the BSON regex at the given index or returns an error if the |
173 | | /// value at that index isn't a regex. |
174 | 0 | pub fn get_regex(&self, index: usize) -> Result<RawRegexRef<'_>> { |
175 | 0 | self.get_with(index, ElementType::RegularExpression, RawBsonRef::as_regex) |
176 | 0 | } |
177 | | |
178 | | /// Gets a reference to the BSON timestamp at the given index or returns an error if the |
179 | | /// value at that index isn't a timestamp. |
180 | 0 | pub fn get_timestamp(&self, index: usize) -> Result<Timestamp> { |
181 | 0 | self.get_with(index, ElementType::Timestamp, RawBsonRef::as_timestamp) |
182 | 0 | } |
183 | | |
184 | | /// Gets the BSON int32 at the given index or returns an error if the value at that index isn't |
185 | | /// a 32-bit integer. |
186 | 0 | pub fn get_i32(&self, index: usize) -> Result<i32> { |
187 | 0 | self.get_with(index, ElementType::Int32, RawBsonRef::as_i32) |
188 | 0 | } |
189 | | |
190 | | /// Gets BSON int64 at the given index or returns an error if the value at that index isn't a |
191 | | /// 64-bit integer. |
192 | 0 | pub fn get_i64(&self, index: usize) -> Result<i64> { |
193 | 0 | self.get_with(index, ElementType::Int64, RawBsonRef::as_i64) |
194 | 0 | } |
195 | | |
196 | | /// Gets a reference to the raw bytes of the [`RawArray`]. |
197 | 0 | pub fn as_bytes(&self) -> &[u8] { |
198 | 0 | self.doc.as_bytes() |
199 | 0 | } |
200 | | |
201 | | /// Whether this array contains any elements or not. |
202 | 0 | pub fn is_empty(&self) -> bool { |
203 | 0 | self.doc.is_empty() |
204 | 0 | } |
205 | | |
206 | | /// Gets an iterator over the elements in the [`RawArray`], |
207 | | /// which yields `Result<RawElement<'_>>` values. These hold a |
208 | | /// reference to the underlying array but do not explicitly |
209 | | /// resolve the values. |
210 | | /// |
211 | | /// This iterator, which underpins the implementation of the |
212 | | /// default iterator, produces `RawElement` objects that hold a |
213 | | /// view onto the array but do not parse out or construct |
214 | | /// values until the `.value()` or `.try_into()` methods are |
215 | | /// called. |
216 | 0 | pub fn iter_elements(&self) -> RawIter<'_> { |
217 | 0 | RawIter::new(&self.doc) |
218 | 0 | } |
219 | | } |
220 | | |
221 | | impl std::fmt::Debug for RawArray { |
222 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
223 | 0 | f.debug_struct("RawArray") |
224 | 0 | .field("data", &hex::encode(self.doc.as_bytes())) |
225 | 0 | .finish() |
226 | 0 | } |
227 | | } |
228 | | |
229 | | impl TryFrom<&RawArray> for Vec<Bson> { |
230 | | type Error = RawError; |
231 | | |
232 | 92.3k | fn try_from(arr: &RawArray) -> RawResult<Vec<Bson>> { |
233 | 92.3k | arr.into_iter() |
234 | 768k | .map(|result| { |
235 | 768k | let rawbson = result?; |
236 | 767k | Bson::try_from(rawbson) |
237 | 768k | }) |
238 | 92.3k | .collect() |
239 | 92.3k | } |
240 | | } |
241 | | |
242 | | impl ToOwned for RawArray { |
243 | | type Owned = RawArrayBuf; |
244 | | |
245 | 92.3k | fn to_owned(&self) -> Self::Owned { |
246 | 92.3k | RawArrayBuf::from_raw_document_buf(self.doc.to_owned()) |
247 | 92.3k | } |
248 | | } |
249 | | |
250 | | impl<'a> From<&'a RawArray> for Cow<'a, RawArray> { |
251 | | fn from(rdr: &'a RawArray) -> Self { |
252 | | Cow::Borrowed(rdr) |
253 | | } |
254 | | } |
255 | | |
256 | | impl<'a> IntoIterator for &'a RawArray { |
257 | | type IntoIter = RawArrayIter<'a>; |
258 | | type Item = RawResult<RawBsonRef<'a>>; |
259 | | |
260 | 92.3k | fn into_iter(self) -> RawArrayIter<'a> { |
261 | 92.3k | RawArrayIter { |
262 | 92.3k | inner: RawIter::new(&self.doc), |
263 | 92.3k | } |
264 | 92.3k | } |
265 | | } |
266 | | |
267 | | /// An iterator over borrowed raw BSON array values. |
268 | | pub struct RawArrayIter<'a> { |
269 | | inner: RawIter<'a>, |
270 | | } |
271 | | |
272 | | impl<'a> Iterator for RawArrayIter<'a> { |
273 | | type Item = RawResult<RawBsonRef<'a>>; |
274 | | |
275 | 859k | fn next(&mut self) -> Option<RawResult<RawBsonRef<'a>>> { |
276 | 859k | match self.inner.next() { |
277 | 767k | Some(Ok(elem)) => match elem.value() { |
278 | 767k | Ok(value) => Some(Ok(value)), |
279 | 315 | Err(e) => Some(Err(e)), |
280 | | }, |
281 | 642 | Some(Err(e)) => Some(Err(e)), |
282 | 91.0k | None => None, |
283 | | } |
284 | 859k | } |
285 | | } |
286 | | |
287 | | #[cfg(feature = "serde")] |
288 | | impl<'de: 'a, 'a> serde::Deserialize<'de> for &'a RawArray { |
289 | 0 | fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> |
290 | 0 | where |
291 | 0 | D: serde::Deserializer<'de>, |
292 | | { |
293 | | use super::serde::OwnedOrBorrowedRawArray; |
294 | 0 | match OwnedOrBorrowedRawArray::deserialize(deserializer)? { |
295 | 0 | OwnedOrBorrowedRawArray::Borrowed(b) => Ok(b), |
296 | 0 | o => Err(serde::de::Error::custom(format!( |
297 | 0 | "expected borrowed raw array, instead got owned {:?}", |
298 | 0 | o |
299 | 0 | ))), |
300 | | } |
301 | 0 | } |
302 | | } |
303 | | |
304 | | #[cfg(feature = "serde")] |
305 | | impl serde::Serialize for &RawArray { |
306 | 0 | fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> |
307 | 0 | where |
308 | 0 | S: serde::Serializer, |
309 | | { |
310 | | struct SeqSerializer<'a>(&'a RawArray); |
311 | | |
312 | | impl serde::Serialize for SeqSerializer<'_> { |
313 | 0 | fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> |
314 | 0 | where |
315 | 0 | S: serde::Serializer, |
316 | | { |
317 | | use serde::ser::SerializeSeq as _; |
318 | 0 | if serializer.is_human_readable() { |
319 | 0 | let mut seq = serializer.serialize_seq(None)?; |
320 | 0 | for v in self.0 { |
321 | 0 | let v = v.map_err(serde::ser::Error::custom)?; |
322 | 0 | seq.serialize_element(&v)?; |
323 | | } |
324 | 0 | seq.end() |
325 | | } else { |
326 | 0 | serializer.serialize_bytes(self.0.as_bytes()) |
327 | | } |
328 | 0 | } |
329 | | } |
330 | | |
331 | 0 | serializer.serialize_newtype_struct(crate::raw::RAW_ARRAY_NEWTYPE, &SeqSerializer(self)) |
332 | 0 | } |
333 | | } |