@@ -2,25 +2,27 @@ pub(crate) mod async_encoding;
22
33use std:: time:: Duration ;
44
5- use bson:: { doc, oid:: ObjectId , Bson , Document } ;
65use serde:: { ser, Deserialize , Deserializer , Serialize , Serializer } ;
76
8- use crate :: error:: { ErrorKind , Result } ;
7+ use crate :: {
8+ bson:: { doc, oid:: ObjectId , Binary , Bson , Document , JavaScriptCodeWithScope , Regex } ,
9+ error:: { ErrorKind , Result } ,
10+ } ;
911
1012/// Coerce numeric types into an `i64` if it would be lossless to do so. If this Bson is not numeric
1113/// or the conversion would be lossy (e.g. 1.5 -> 1), this returns `None`.
1214pub ( crate ) fn get_int ( val : & Bson ) -> Option < i64 > {
1315 match * val {
14- Bson :: I32 ( i) => Some ( i64:: from ( i) ) ,
15- Bson :: I64 ( i) => Some ( i) ,
16- Bson :: FloatingPoint ( f) if f == f as i64 as f64 => Some ( f as i64 ) ,
16+ Bson :: Int32 ( i) => Some ( i64:: from ( i) ) ,
17+ Bson :: Int64 ( i) => Some ( i) ,
18+ Bson :: Double ( f) if f == f as i64 as f64 => Some ( f as i64 ) ,
1719 _ => None ,
1820 }
1921}
2022
2123pub ( crate ) fn add_id ( doc : & mut Document ) {
2224 doc. entry ( "_id" . to_string ( ) )
23- . or_insert_with ( || Bson :: ObjectId ( ObjectId :: new ( ) . unwrap ( ) ) ) ;
25+ . or_insert_with ( || Bson :: ObjectId ( ObjectId :: new ( ) ) ) ;
2426}
2527
2628pub ( crate ) fn to_bson_array ( docs : & [ Document ] ) -> Bson {
@@ -61,12 +63,15 @@ pub(crate) fn update_document_check(update: &Document) -> Result<()> {
6163 }
6264}
6365
64- pub ( crate ) fn serialize_duration_as_i64_millis < S : Serializer > (
66+ pub ( crate ) fn serialize_duration_as_int_millis < S : Serializer > (
6567 val : & Option < Duration > ,
6668 serializer : S ,
6769) -> std:: result:: Result < S :: Ok , S :: Error > {
6870 match val {
69- Some ( duration) => serializer. serialize_i64 ( duration. as_millis ( ) as i64 ) ,
71+ Some ( duration) if duration. as_millis ( ) > i32:: MAX as u128 => {
72+ serializer. serialize_i64 ( duration. as_millis ( ) as i64 )
73+ }
74+ Some ( duration) => serializer. serialize_i32 ( duration. as_millis ( ) as i32 ) ,
7075 None => serializer. serialize_none ( ) ,
7176 }
7277}
@@ -128,7 +133,7 @@ pub fn doc_size_bytes(doc: &Document) -> usize {
128133
129134pub fn size_bytes ( val : & Bson ) -> usize {
130135 match val {
131- Bson :: FloatingPoint ( _) => 8 ,
136+ Bson :: Double ( _) => 8 ,
132137 //
133138 // * length prefix (4 bytes)
134139 // * number of UTF-8 bytes
@@ -158,7 +163,9 @@ pub fn size_bytes(val: &Bson) -> usize {
158163 // for $pattern and $opts:
159164 // * number of UTF-8 bytes
160165 // * null terminator (1 byte)
161- Bson :: RegExp ( pattern, opts) => pattern. len ( ) + 1 + opts. len ( ) + 1 ,
166+ Bson :: RegularExpression ( Regex { pattern, options } ) => {
167+ pattern. len ( ) + 1 + options. len ( ) + 1
168+ }
162169 //
163170 // * length prefix (4 bytes)
164171 // * number of UTF-8 bytes
@@ -170,24 +177,37 @@ pub fn size_bytes(val: &Bson) -> usize {
170177 // * number of UTF-8 bytes in code
171178 // * null terminator for code (1 byte)
172179 // * length of document
173- Bson :: JavaScriptCodeWithScope ( code, scope) => {
180+ Bson :: JavaScriptCodeWithScope ( JavaScriptCodeWithScope { code, scope } ) => {
174181 4 + 4 + code. len ( ) + 1 + doc_size_bytes ( scope)
175182 }
176- Bson :: I32 ( _) => 4 ,
177- Bson :: I64 ( _) => 8 ,
178- Bson :: TimeStamp ( _) => 8 ,
183+ Bson :: Int32 ( _) => 4 ,
184+ Bson :: Int64 ( _) => 8 ,
185+ Bson :: Timestamp ( _) => 8 ,
179186 //
180187 // * i32 length prefix (4 bytes)
181188 // * subtype (1 byte)
182189 // * number of bytes
183- Bson :: Binary ( _ , bytes) => 4 + 1 + bytes. len ( ) ,
190+ Bson :: Binary ( Binary { bytes, .. } ) => 4 + 1 + bytes. len ( ) ,
184191 Bson :: ObjectId ( _) => 12 ,
185- Bson :: UtcDatetime ( _) => 8 ,
192+ Bson :: DateTime ( _) => 8 ,
186193 //
187194 // * i32 length prefix (4 bytes)
188195 // * subtype (1 byte)
189196 // * number of UTF-8 bytes
190197 Bson :: Symbol ( s) => 4 + 1 + s. len ( ) ,
198+ Bson :: Decimal128 ( ..) => 128 / 8 ,
199+ Bson :: Undefined | Bson :: MaxKey | Bson :: MinKey => 0 ,
200+ // DbPointer doesn't have public details exposed by the BSON library, but it comprises of a
201+ // namespace and an ObjectId. Since our methods to calculate the size of BSON values are
202+ // only used to estimate the cutoff for batches when making a large insert, we can just
203+ // assume the largest possible size for a namespace, which is 120 bytes. Therefore, the size
204+ // is:
205+ //
206+ // * i32 length prefix (4 bytes)
207+ // * namespace (120 bytes)
208+ // * null terminator (1 byte)
209+ // * objectid (12 bytes)
210+ Bson :: DbPointer ( ..) => 4 + 120 + 1 + 12 ,
191211 }
192212}
193213
@@ -209,7 +229,16 @@ fn num_decimal_digits(n: usize) -> usize {
209229
210230#[ cfg( test) ]
211231mod test {
212- use bson:: { doc, oid:: ObjectId , spec:: BinarySubtype , Bson } ;
232+ use crate :: bson:: {
233+ doc,
234+ oid:: ObjectId ,
235+ spec:: BinarySubtype ,
236+ Binary ,
237+ Bson ,
238+ JavaScriptCodeWithScope ,
239+ Regex ,
240+ Timestamp ,
241+ } ;
213242 use chrono:: { DateTime , NaiveDateTime , Utc } ;
214243
215244 use super :: doc_size_bytes;
@@ -220,23 +249,23 @@ mod test {
220249 let doc = doc ! {
221250 "double" : -12.3 ,
222251 "string" : "foo" ,
223- "array" : [ "foobar" , -7 , Bson :: Null , Bson :: TimeStamp ( 1278 ) , false ] ,
252+ "array" : [ "foobar" , -7 , Bson :: Null , Bson :: Timestamp ( Timestamp { time : 12345 , increment : 67890 } ) , false ] ,
224253 "document" : {
225254 "x" : 1 ,
226255 "yyz" : "Rush is one of the greatest bands of all time" ,
227256 } ,
228257 "bool" : true ,
229258 "null" : Bson :: Null ,
230- "regex" : Bson :: RegExp ( "foobar" . into( ) , "i" . into( ) ) ,
259+ "regex" : Bson :: RegularExpression ( Regex { pattern : "foobar" . into( ) , options : "i" . into( ) } ) ,
231260 "code" : Bson :: JavaScriptCode ( "foo(x) { return x + 1; }" . into( ) ) ,
232- "code with scope" : Bson :: JavaScriptCodeWithScope (
233- "foo(x) { return x + y; }" . into( ) ,
234- doc! { "y" : -17 } ,
235- ) ,
261+ "code with scope" : Bson :: JavaScriptCodeWithScope ( JavaScriptCodeWithScope {
262+ code : "foo(x) { return x + y; }" . into( ) ,
263+ scope : doc! { "y" : -17 } ,
264+ } ) ,
236265 "i32" : 12i32 ,
237266 "i64" : -126i64 ,
238- "timestamp" : Bson :: TimeStamp ( 1223334444 ) ,
239- "binary" : Bson :: Binary ( BinarySubtype :: Generic , vec![ 3 , 222 , 11 ] ) ,
267+ "timestamp" : Bson :: Timestamp ( Timestamp { time : 12233 , increment : 34444 } ) ,
268+ "binary" : Bson :: Binary ( Binary { subtype : BinarySubtype :: Generic , bytes : vec![ 3 , 222 , 11 ] } ) ,
240269 "objectid" : ObjectId :: with_bytes( [ 1 ; 12 ] ) ,
241270 "datetime" : DateTime :: from_utc(
242271 NaiveDateTime :: from_timestamp( 4444333221 , 0 ) ,
@@ -248,7 +277,7 @@ mod test {
248277 let size_bytes = doc_size_bytes ( & doc) ;
249278
250279 let mut serialized_bytes = Vec :: new ( ) ;
251- bson :: encode_document ( & mut serialized_bytes, & doc ) . unwrap ( ) ;
280+ doc . to_writer ( & mut serialized_bytes) . unwrap ( ) ;
252281
253282 assert_eq ! ( size_bytes, serialized_bytes. len( ) ) ;
254283 }
0 commit comments