bson 4.2.2 → 4.3.0.beta

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e76c5872004b8c218e35db5ae4db7e2a0f69449
4
- data.tar.gz: 40dc1aac62c0f7a59eed2a6a9619743927a66ae6
3
+ metadata.gz: 3a8c878410e043f1b920f996932401686eb2ef59
4
+ data.tar.gz: e459f34a04cbc3cc71f4723e95225fc69af98796
5
5
  SHA512:
6
- metadata.gz: 5e820f483f475073365955ec222c92771ca5ed5bc2547c82eeabc353a1dd9153e1a5fff8a878428ba0e781e8f2c8f2d341b858423407469d7d6947324f3ff3b8
7
- data.tar.gz: c0fdd409db1055211502f7f2b3527d298d6e0e6ece5bde64418b0291e709e50eda0471951ccc10c57a86f9cdcd7e2ee9353bda19c7fd02f61fcc593612db65c0
6
+ metadata.gz: e0ba9d2a810a8dd77520b0605b351dfc9c06525dab2998f77755480e1600a2d799dd6ca2084268a903e335e4336b6c96a829c2943cc2f7adeea55ee8b1bf1f15
7
+ data.tar.gz: 54c0d9e149895d20f857273a392d4895b55c61f2642d5c6561a0ce2478707f56a0bf810c8ea5220a1fbdf1b69d59f6ce0ced391cbd00e7dd4f8b25ade6418d6d
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -26,6 +26,14 @@
26
26
  #define HOST_NAME_HASH_MAX 256
27
27
  #endif
28
28
 
29
+ #define BSON_TYPE_DOUBLE 1
30
+ #define BSON_TYPE_STRING 2
31
+ #define BSON_TYPE_OBJECT 3
32
+ #define BSON_TYPE_ARRAY 4
33
+ #define BSON_TYPE_INT32 16
34
+ #define BSON_TYPE_INT64 18
35
+ #define BSON_TYPE_BOOLEAN 8
36
+
29
37
  typedef struct {
30
38
  size_t size;
31
39
  size_t write_position;
@@ -61,6 +69,8 @@ static VALUE rb_bson_byte_buffer_get_double(VALUE self);
61
69
  static VALUE rb_bson_byte_buffer_get_int32(VALUE self);
62
70
  static VALUE rb_bson_byte_buffer_get_int64(VALUE self);
63
71
  static VALUE rb_bson_byte_buffer_get_string(VALUE self);
72
+ static VALUE rb_bson_byte_buffer_get_hash(VALUE self);
73
+ static VALUE rb_bson_byte_buffer_get_array(VALUE self);
64
74
  static VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte);
65
75
  static VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes);
66
76
  static VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE string);
@@ -69,6 +79,8 @@ static VALUE rb_bson_byte_buffer_put_double(VALUE self, VALUE f);
69
79
  static VALUE rb_bson_byte_buffer_put_int32(VALUE self, VALUE i);
70
80
  static VALUE rb_bson_byte_buffer_put_int64(VALUE self, VALUE i);
71
81
  static VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string);
82
+ static VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash, VALUE validating_keys);
83
+ static VALUE rb_bson_byte_buffer_put_array(VALUE self, VALUE array, VALUE validating_keys);
72
84
  static VALUE rb_bson_byte_buffer_read_position(VALUE self);
73
85
  static VALUE rb_bson_byte_buffer_replace_int32(VALUE self, VALUE index, VALUE i);
74
86
  static VALUE rb_bson_byte_buffer_rewind(VALUE self);
@@ -87,6 +99,28 @@ static const rb_data_type_t rb_byte_buffer_data_type = {
87
99
  { NULL, rb_bson_byte_buffer_free, rb_bson_byte_buffer_memsize }
88
100
  };
89
101
 
102
+ static uint8_t pvt_get_type_byte(byte_buffer_t *b);
103
+ static VALUE pvt_get_int32(byte_buffer_t *b);
104
+ static VALUE pvt_get_int64(byte_buffer_t *b);
105
+ static VALUE pvt_get_double(byte_buffer_t *b);
106
+ static VALUE pvt_get_string(byte_buffer_t *b);
107
+ static VALUE pvt_get_boolean(byte_buffer_t *b);
108
+
109
+
110
+ static VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type);
111
+ static void pvt_replace_int32(byte_buffer_t *b, int32_t position, int32_t newval);
112
+ static void pvt_skip_cstring(byte_buffer_t *b);
113
+ static void pvt_validate_length(byte_buffer_t *b);
114
+
115
+
116
+ static void pvt_put_field(byte_buffer_t *b, VALUE rb_buffer, VALUE val, VALUE validating_keys);
117
+ static void pvt_put_byte(byte_buffer_t *b, const char byte);
118
+ static void pvt_put_int32(byte_buffer_t *b, const int32_t i32);
119
+ static void pvt_put_int64(byte_buffer_t *b, const int64_t i);
120
+ static void pvt_put_double(byte_buffer_t *b, double f);
121
+ static void pvt_put_cstring(byte_buffer_t *b, VALUE string);
122
+ static void pvt_put_bson_key(byte_buffer_t *b, VALUE string, VALUE validating_keys);
123
+
90
124
  /**
91
125
  * Holds the machine id hash for object id generation.
92
126
  */
@@ -97,6 +131,10 @@ static char rb_bson_machine_id_hash[HOST_NAME_HASH_MAX];
97
131
  */
98
132
  static uint32_t rb_bson_object_id_counter;
99
133
 
134
+
135
+ static VALUE rb_bson_registry;
136
+
137
+ static VALUE rb_bson_illegal_key;
100
138
  /**
101
139
  * Initialize the bson_native extension.
102
140
  */
@@ -111,6 +149,8 @@ void Init_bson_native()
111
149
  VALUE rb_digest_class = rb_const_get(rb_cObject, rb_intern("Digest"));
112
150
  VALUE rb_md5_class = rb_const_get(rb_digest_class, rb_intern("MD5"));
113
151
 
152
+ rb_bson_illegal_key = rb_const_get(rb_const_get(rb_bson_module, rb_intern("String")),rb_intern("IllegalKey"));
153
+
114
154
  rb_define_alloc_func(rb_byte_buffer_class, rb_bson_byte_buffer_allocate);
115
155
  rb_define_method(rb_byte_buffer_class, "initialize", rb_bson_byte_buffer_initialize, -1);
116
156
  rb_define_method(rb_byte_buffer_class, "length", rb_bson_byte_buffer_length, 0);
@@ -119,6 +159,9 @@ void Init_bson_native()
119
159
  rb_define_method(rb_byte_buffer_class, "get_cstring", rb_bson_byte_buffer_get_cstring, 0);
120
160
  rb_define_method(rb_byte_buffer_class, "get_decimal128_bytes", rb_bson_byte_buffer_get_decimal128_bytes, 0);
121
161
  rb_define_method(rb_byte_buffer_class, "get_double", rb_bson_byte_buffer_get_double, 0);
162
+ rb_define_method(rb_byte_buffer_class, "get_hash", rb_bson_byte_buffer_get_hash, 0);
163
+ rb_define_method(rb_byte_buffer_class, "get_array", rb_bson_byte_buffer_get_array, 0);
164
+
122
165
  rb_define_method(rb_byte_buffer_class, "get_int32", rb_bson_byte_buffer_get_int32, 0);
123
166
  rb_define_method(rb_byte_buffer_class, "get_int64", rb_bson_byte_buffer_get_int64, 0);
124
167
  rb_define_method(rb_byte_buffer_class, "get_string", rb_bson_byte_buffer_get_string, 0);
@@ -137,6 +180,9 @@ void Init_bson_native()
137
180
  rb_define_method(rb_byte_buffer_class, "to_s", rb_bson_byte_buffer_to_s, 0);
138
181
  rb_define_method(rb_bson_object_id_generator_class, "next_object_id", rb_bson_object_id_generator_next, -1);
139
182
 
183
+ rb_define_method(rb_byte_buffer_class, "put_hash", rb_bson_byte_buffer_put_hash, 2);
184
+ rb_define_method(rb_byte_buffer_class, "put_array", rb_bson_byte_buffer_put_array, 2);
185
+
140
186
  // Get the object id machine id and hash it.
141
187
  rb_require("digest/md5");
142
188
  gethostname(rb_bson_machine_id, sizeof(rb_bson_machine_id));
@@ -145,6 +191,8 @@ void Init_bson_native()
145
191
 
146
192
  // Set the object id counter to a random number
147
193
  rb_bson_object_id_counter = FIX2INT(rb_funcall(rb_mKernel, rb_intern("rand"), 1, INT2FIX(0x1000000)));
194
+
195
+ rb_bson_registry = rb_const_get(rb_bson_module, rb_intern("Registry"));
148
196
  }
149
197
 
150
198
  void rb_bson_generate_machine_id(VALUE rb_md5_class, char *rb_bson_machine_id)
@@ -180,6 +228,285 @@ VALUE rb_bson_byte_buffer_initialize(int argc, VALUE *argv, VALUE self)
180
228
  return self;
181
229
  }
182
230
 
231
+ static int fits_int32(int64_t i64){
232
+ return i64 >= INT32_MIN && i64 <= INT32_MAX;
233
+ }
234
+
235
+ /* write the byte denoting the BSON type for the passed object*/
236
+ void pvt_put_type_byte(byte_buffer_t *b, VALUE val){
237
+ switch(TYPE(val)){
238
+ case T_BIGNUM:
239
+ case T_FIXNUM:
240
+ if(fits_int32(NUM2LL(val))){
241
+ pvt_put_byte(b, BSON_TYPE_INT32);
242
+ }else{
243
+ pvt_put_byte(b, BSON_TYPE_INT64);
244
+ }
245
+ break;
246
+ case T_STRING:
247
+ pvt_put_byte(b, BSON_TYPE_STRING);
248
+ break;
249
+ case T_ARRAY:
250
+ pvt_put_byte(b, BSON_TYPE_ARRAY);
251
+ break;
252
+ case T_TRUE:
253
+ case T_FALSE:
254
+ pvt_put_byte(b, BSON_TYPE_BOOLEAN);
255
+ break;
256
+ case T_HASH:
257
+ pvt_put_byte(b, BSON_TYPE_OBJECT);
258
+ break;
259
+ case T_FLOAT:
260
+ pvt_put_byte(b, BSON_TYPE_DOUBLE);
261
+ break;
262
+ default:{
263
+ VALUE type = rb_funcall(val, rb_intern("bson_type"),0);
264
+ pvt_put_byte(b, *RSTRING_PTR(type));
265
+ break;
266
+ }
267
+ }
268
+ }
269
+
270
+ void pvt_put_field(byte_buffer_t *b, VALUE rb_buffer, VALUE val, VALUE validating_keys){
271
+ switch(TYPE(val)){
272
+ case T_BIGNUM:
273
+ case T_FIXNUM:{
274
+ int64_t i64= NUM2LL(val);
275
+ if(fits_int32(i64)){
276
+ pvt_put_int32(b, (int32_t)i64);
277
+ }else{
278
+ pvt_put_int64(b, i64);
279
+ }
280
+ break;
281
+ }
282
+ case T_FLOAT:
283
+ pvt_put_double(b, NUM2DBL(val));
284
+ break;
285
+ case T_ARRAY:
286
+ rb_bson_byte_buffer_put_array(rb_buffer, val, validating_keys);
287
+ break;
288
+ case T_TRUE:
289
+ pvt_put_byte(b, 1);
290
+ break;
291
+ case T_FALSE:
292
+ pvt_put_byte(b, 0);
293
+ break;
294
+ case T_HASH:
295
+ rb_bson_byte_buffer_put_hash(rb_buffer, val, validating_keys);
296
+ break;
297
+ default:{
298
+ rb_funcall(val, rb_intern("to_bson"), 2, rb_buffer, validating_keys);
299
+ break;
300
+ }
301
+ }
302
+ }
303
+
304
+ typedef struct{
305
+ byte_buffer_t *b;
306
+ VALUE buffer;
307
+ VALUE validating_keys;
308
+ } put_hash_context;
309
+
310
+ static int put_hash_callback(VALUE key, VALUE val, VALUE context){
311
+ VALUE buffer = ((put_hash_context*)context)->buffer;
312
+ VALUE validating_keys = ((put_hash_context*)context)->validating_keys;
313
+ byte_buffer_t *b = ((put_hash_context*)context)->b;
314
+
315
+ pvt_put_type_byte(b, val);
316
+
317
+ switch(TYPE(key)){
318
+ case T_STRING:
319
+ pvt_put_bson_key(b, key, validating_keys);
320
+ break;
321
+ case T_SYMBOL:
322
+ pvt_put_bson_key(b, rb_sym_to_s(key), validating_keys);
323
+ break;
324
+ default:
325
+ rb_bson_byte_buffer_put_cstring(buffer, rb_funcall(key, rb_intern("to_bson_key"), 1, validating_keys));
326
+ }
327
+
328
+ pvt_put_field(b, buffer, val, validating_keys);
329
+ return ST_CONTINUE;
330
+ }
331
+
332
+ /**
333
+ * serializes a hash into the byte buffer
334
+ */
335
+ VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash, VALUE validating_keys){
336
+ byte_buffer_t *b = NULL;
337
+ put_hash_context context = {0};
338
+ size_t position = 0;
339
+ size_t new_position = 0;
340
+ int32_t new_length = 0;
341
+
342
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
343
+ Check_Type(hash, T_HASH);
344
+
345
+ position = READ_SIZE(b);
346
+
347
+ /* insert length placeholder */
348
+ pvt_put_int32(b, 0);
349
+ context.buffer = self;
350
+ context.validating_keys = validating_keys;
351
+ context.b = b;
352
+
353
+ rb_hash_foreach(hash, put_hash_callback, (VALUE)&context);
354
+ pvt_put_byte(b, 0);
355
+
356
+ /* update length placeholder with actual value */
357
+ new_position = READ_SIZE(b);
358
+ new_length = new_position - position;
359
+ pvt_replace_int32(b, position, new_length);
360
+
361
+ return self;
362
+ }
363
+
364
+ static const char *index_strings[] = {
365
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
366
+ "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21",
367
+ "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32",
368
+ "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43",
369
+ "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54",
370
+ "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65",
371
+ "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76",
372
+ "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87",
373
+ "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98",
374
+ "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
375
+ "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120",
376
+ "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131",
377
+ "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142",
378
+ "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153",
379
+ "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164",
380
+ "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175",
381
+ "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186",
382
+ "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197",
383
+ "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208",
384
+ "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
385
+ "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230",
386
+ "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241",
387
+ "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252",
388
+ "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263",
389
+ "264", "265", "266", "267", "268", "269", "270", "271", "272", "273", "274",
390
+ "275", "276", "277", "278", "279", "280", "281", "282", "283", "284", "285",
391
+ "286", "287", "288", "289", "290", "291", "292", "293", "294", "295", "296",
392
+ "297", "298", "299", "300", "301", "302", "303", "304", "305", "306", "307",
393
+ "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318",
394
+ "319", "320", "321", "322", "323", "324", "325", "326", "327", "328", "329",
395
+ "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", "340",
396
+ "341", "342", "343", "344", "345", "346", "347", "348", "349", "350", "351",
397
+ "352", "353", "354", "355", "356", "357", "358", "359", "360", "361", "362",
398
+ "363", "364", "365", "366", "367", "368", "369", "370", "371", "372", "373",
399
+ "374", "375", "376", "377", "378", "379", "380", "381", "382", "383", "384",
400
+ "385", "386", "387", "388", "389", "390", "391", "392", "393", "394", "395",
401
+ "396", "397", "398", "399", "400", "401", "402", "403", "404", "405", "406",
402
+ "407", "408", "409", "410", "411", "412", "413", "414", "415", "416", "417",
403
+ "418", "419", "420", "421", "422", "423", "424", "425", "426", "427", "428",
404
+ "429", "430", "431", "432", "433", "434", "435", "436", "437", "438", "439",
405
+ "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", "450",
406
+ "451", "452", "453", "454", "455", "456", "457", "458", "459", "460", "461",
407
+ "462", "463", "464", "465", "466", "467", "468", "469", "470", "471", "472",
408
+ "473", "474", "475", "476", "477", "478", "479", "480", "481", "482", "483",
409
+ "484", "485", "486", "487", "488", "489", "490", "491", "492", "493", "494",
410
+ "495", "496", "497", "498", "499", "500", "501", "502", "503", "504", "505",
411
+ "506", "507", "508", "509", "510", "511", "512", "513", "514", "515", "516",
412
+ "517", "518", "519", "520", "521", "522", "523", "524", "525", "526", "527",
413
+ "528", "529", "530", "531", "532", "533", "534", "535", "536", "537", "538",
414
+ "539", "540", "541", "542", "543", "544", "545", "546", "547", "548", "549",
415
+ "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", "560",
416
+ "561", "562", "563", "564", "565", "566", "567", "568", "569", "570", "571",
417
+ "572", "573", "574", "575", "576", "577", "578", "579", "580", "581", "582",
418
+ "583", "584", "585", "586", "587", "588", "589", "590", "591", "592", "593",
419
+ "594", "595", "596", "597", "598", "599", "600", "601", "602", "603", "604",
420
+ "605", "606", "607", "608", "609", "610", "611", "612", "613", "614", "615",
421
+ "616", "617", "618", "619", "620", "621", "622", "623", "624", "625", "626",
422
+ "627", "628", "629", "630", "631", "632", "633", "634", "635", "636", "637",
423
+ "638", "639", "640", "641", "642", "643", "644", "645", "646", "647", "648",
424
+ "649", "650", "651", "652", "653", "654", "655", "656", "657", "658", "659",
425
+ "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", "670",
426
+ "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681",
427
+ "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692",
428
+ "693", "694", "695", "696", "697", "698", "699", "700", "701", "702", "703",
429
+ "704", "705", "706", "707", "708", "709", "710", "711", "712", "713", "714",
430
+ "715", "716", "717", "718", "719", "720", "721", "722", "723", "724", "725",
431
+ "726", "727", "728", "729", "730", "731", "732", "733", "734", "735", "736",
432
+ "737", "738", "739", "740", "741", "742", "743", "744", "745", "746", "747",
433
+ "748", "749", "750", "751", "752", "753", "754", "755", "756", "757", "758",
434
+ "759", "760", "761", "762", "763", "764", "765", "766", "767", "768", "769",
435
+ "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", "780",
436
+ "781", "782", "783", "784", "785", "786", "787", "788", "789", "790", "791",
437
+ "792", "793", "794", "795", "796", "797", "798", "799", "800", "801", "802",
438
+ "803", "804", "805", "806", "807", "808", "809", "810", "811", "812", "813",
439
+ "814", "815", "816", "817", "818", "819", "820", "821", "822", "823", "824",
440
+ "825", "826", "827", "828", "829", "830", "831", "832", "833", "834", "835",
441
+ "836", "837", "838", "839", "840", "841", "842", "843", "844", "845", "846",
442
+ "847", "848", "849", "850", "851", "852", "853", "854", "855", "856", "857",
443
+ "858", "859", "860", "861", "862", "863", "864", "865", "866", "867", "868",
444
+ "869", "870", "871", "872", "873", "874", "875", "876", "877", "878", "879",
445
+ "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", "890",
446
+ "891", "892", "893", "894", "895", "896", "897", "898", "899", "900", "901",
447
+ "902", "903", "904", "905", "906", "907", "908", "909", "910", "911", "912",
448
+ "913", "914", "915", "916", "917", "918", "919", "920", "921", "922", "923",
449
+ "924", "925", "926", "927", "928", "929", "930", "931", "932", "933", "934",
450
+ "935", "936", "937", "938", "939", "940", "941", "942", "943", "944", "945",
451
+ "946", "947", "948", "949", "950", "951", "952", "953", "954", "955", "956",
452
+ "957", "958", "959", "960", "961", "962", "963", "964", "965", "966", "967",
453
+ "968", "969", "970", "971", "972", "973", "974", "975", "976", "977", "978",
454
+ "979", "980", "981", "982", "983", "984", "985", "986", "987", "988", "989",
455
+ "990", "991", "992", "993", "994", "995", "996", "997", "998", "999"};
456
+
457
+ /**
458
+ * Writes an array index to the byte buffer.
459
+ */
460
+ void pvt_put_array_index(byte_buffer_t *b, int32_t index)
461
+ {
462
+ char buffer[16];
463
+ const char *c_str = NULL;
464
+
465
+ if (index < 1000) {
466
+ c_str = index_strings[index];
467
+ } else {
468
+ c_str = buffer;
469
+ snprintf(buffer, sizeof(buffer), "%d", index);
470
+ }
471
+ size_t length = strlen(c_str) + 1;
472
+ ENSURE_BSON_WRITE(b, length);
473
+ memcpy(WRITE_PTR(b), c_str, length);
474
+ b->write_position += length;
475
+ }
476
+
477
+ /**
478
+ * serializes an array into the byte buffer
479
+ */
480
+ VALUE rb_bson_byte_buffer_put_array(VALUE self, VALUE array, VALUE validating_keys){
481
+ byte_buffer_t *b = NULL;
482
+ size_t new_position = 0;
483
+ int32_t new_length = 0;
484
+ size_t position = 0;
485
+ VALUE *array_element = NULL;
486
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
487
+ Check_Type(array, T_ARRAY);
488
+
489
+ position = READ_SIZE(b);
490
+ /* insert length placeholder */
491
+ pvt_put_int32(b, 0);
492
+
493
+ array_element = RARRAY_PTR(array);
494
+
495
+ for(int32_t index=0; index < RARRAY_LEN(array); index++, array_element++){
496
+ pvt_put_type_byte(b, *array_element);
497
+ pvt_put_array_index(b,index);
498
+ pvt_put_field(b, self, *array_element, validating_keys);
499
+ }
500
+ pvt_put_byte(b, 0);
501
+
502
+ /* update length placeholder */
503
+ new_position = READ_SIZE(b);
504
+ new_length = new_position - position;
505
+ pvt_replace_int32(b, position, new_length);
506
+
507
+ return self;
508
+ }
509
+
183
510
  /**
184
511
  * Get the length of the buffer.
185
512
  */
@@ -205,6 +532,13 @@ VALUE rb_bson_byte_buffer_get_byte(VALUE self)
205
532
  return byte;
206
533
  }
207
534
 
535
+ uint8_t pvt_get_type_byte(byte_buffer_t *b){
536
+ ENSURE_BSON_READ(b, 1);
537
+ int8_t byte = *READ_PTR(b);
538
+ b->read_position += 1;
539
+ return (uint8_t)byte;
540
+ }
541
+
208
542
  /**
209
543
  * Get bytes from the buffer.
210
544
  */
@@ -221,6 +555,14 @@ VALUE rb_bson_byte_buffer_get_bytes(VALUE self, VALUE i)
221
555
  return bytes;
222
556
  }
223
557
 
558
+ VALUE pvt_get_boolean(byte_buffer_t *b){
559
+ VALUE result = Qnil;
560
+ ENSURE_BSON_READ(b, 1);
561
+ result = *READ_PTR(b) == 1 ? Qtrue: Qfalse;
562
+ b->read_position += 1;
563
+ return result;
564
+ }
565
+
224
566
  /**
225
567
  * Get a cstring from the buffer.
226
568
  */
@@ -238,6 +580,17 @@ VALUE rb_bson_byte_buffer_get_cstring(VALUE self)
238
580
  return string;
239
581
  }
240
582
 
583
+ /**
584
+ * Reads but does not return a cstring from the buffer.
585
+ */
586
+ void pvt_skip_cstring(byte_buffer_t *b)
587
+ {
588
+ int length;
589
+ length = (int)strlen(READ_PTR(b));
590
+ ENSURE_BSON_READ(b, length);
591
+ b->read_position += length + 1;
592
+ }
593
+
241
594
  /**
242
595
  * Get the 16 bytes representing the decimal128 from the buffer.
243
596
  */
@@ -259,9 +612,15 @@ VALUE rb_bson_byte_buffer_get_decimal128_bytes(VALUE self)
259
612
  VALUE rb_bson_byte_buffer_get_double(VALUE self)
260
613
  {
261
614
  byte_buffer_t *b;
262
- double d;
263
615
 
264
616
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
617
+ return pvt_get_double(b);
618
+ }
619
+
620
+ VALUE pvt_get_double(byte_buffer_t *b)
621
+ {
622
+ double d;
623
+
265
624
  ENSURE_BSON_READ(b, 8);
266
625
  memcpy(&d, READ_PTR(b), 8);
267
626
  b->read_position += 8;
@@ -274,9 +633,15 @@ VALUE rb_bson_byte_buffer_get_double(VALUE self)
274
633
  VALUE rb_bson_byte_buffer_get_int32(VALUE self)
275
634
  {
276
635
  byte_buffer_t *b;
277
- int32_t i32;
278
636
 
279
637
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
638
+ return pvt_get_int32(b);
639
+ }
640
+
641
+ VALUE pvt_get_int32(byte_buffer_t *b)
642
+ {
643
+ int32_t i32;
644
+
280
645
  ENSURE_BSON_READ(b, 4);
281
646
  memcpy(&i32, READ_PTR(b), 4);
282
647
  b->read_position += 4;
@@ -289,9 +654,14 @@ VALUE rb_bson_byte_buffer_get_int32(VALUE self)
289
654
  VALUE rb_bson_byte_buffer_get_int64(VALUE self)
290
655
  {
291
656
  byte_buffer_t *b;
657
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
658
+ return pvt_get_int64(b);
659
+ }
660
+
661
+ VALUE pvt_get_int64(byte_buffer_t *b)
662
+ {
292
663
  int64_t i64;
293
664
 
294
- TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
295
665
  ENSURE_BSON_READ(b, 8);
296
666
  memcpy(&i64, READ_PTR(b), 8);
297
667
  b->read_position += 8;
@@ -304,11 +674,17 @@ VALUE rb_bson_byte_buffer_get_int64(VALUE self)
304
674
  VALUE rb_bson_byte_buffer_get_string(VALUE self)
305
675
  {
306
676
  byte_buffer_t *b;
677
+
678
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
679
+ return pvt_get_string(b);
680
+ }
681
+
682
+ VALUE pvt_get_string(byte_buffer_t *b)
683
+ {
307
684
  int32_t length;
308
685
  int32_t length_le;
309
686
  VALUE string;
310
687
 
311
- TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
312
688
  ENSURE_BSON_READ(b, 4);
313
689
  memcpy(&length, READ_PTR(b), 4);
314
690
  length_le = BSON_UINT32_FROM_LE(length);
@@ -319,6 +695,64 @@ VALUE rb_bson_byte_buffer_get_string(VALUE self)
319
695
  return string;
320
696
  }
321
697
 
698
+
699
+ VALUE rb_bson_byte_buffer_get_hash(VALUE self){
700
+ VALUE doc = Qnil;
701
+ byte_buffer_t *b=NULL;
702
+ uint8_t type;
703
+ VALUE cDocument = rb_const_get(rb_const_get(rb_cObject, rb_intern("BSON")), rb_intern("Document"));
704
+
705
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
706
+
707
+ pvt_validate_length(b);
708
+
709
+ doc = rb_funcall(cDocument, rb_intern("allocate"),0);
710
+
711
+ while((type = pvt_get_type_byte(b)) != 0){
712
+ VALUE field = rb_bson_byte_buffer_get_cstring(self);
713
+ rb_hash_aset(doc, field, pvt_read_field(b, self, type));
714
+ }
715
+ return doc;
716
+ }
717
+
718
+ VALUE rb_bson_byte_buffer_get_array(VALUE self){
719
+ byte_buffer_t *b;
720
+ VALUE array = Qnil;
721
+ uint8_t type;
722
+
723
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
724
+
725
+ pvt_validate_length(b);
726
+
727
+ array = rb_ary_new();
728
+ while((type = pvt_get_type_byte(b)) != 0){
729
+ pvt_skip_cstring(b);
730
+ rb_ary_push(array, pvt_read_field(b, self, type));
731
+ }
732
+ return array;
733
+ }
734
+
735
+ /**
736
+ * Read a single field from a hash or array
737
+ */
738
+ VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type){
739
+ switch(type) {
740
+ case BSON_TYPE_INT32: return pvt_get_int32(b);
741
+ case BSON_TYPE_INT64: return pvt_get_int64(b);
742
+ case BSON_TYPE_DOUBLE: return pvt_get_double(b);
743
+ case BSON_TYPE_STRING: return pvt_get_string(b);
744
+ case BSON_TYPE_ARRAY: return rb_bson_byte_buffer_get_array(rb_buffer);
745
+ case BSON_TYPE_OBJECT: return rb_bson_byte_buffer_get_hash(rb_buffer);
746
+ case BSON_TYPE_BOOLEAN: return pvt_get_boolean(b);
747
+ default:
748
+ {
749
+ VALUE klass = rb_funcall(rb_bson_registry,rb_intern("get"),1, INT2FIX(type));
750
+ VALUE value = rb_funcall(klass, rb_intern("from_bson"),1, rb_buffer);
751
+ return value;
752
+ }
753
+ }
754
+ }
755
+
322
756
  /**
323
757
  * Writes a byte to the byte buffer.
324
758
  */
@@ -335,6 +769,13 @@ VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte)
335
769
  return self;
336
770
  }
337
771
 
772
+ void pvt_put_byte( byte_buffer_t *b, const char byte)
773
+ {
774
+ ENSURE_BSON_WRITE(b, 1);
775
+ *WRITE_PTR(b) = byte;
776
+ b->write_position += 1;
777
+
778
+ }
338
779
  /**
339
780
  * Writes bytes to the byte buffer.
340
781
  */
@@ -357,18 +798,37 @@ VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes)
357
798
  VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE string)
358
799
  {
359
800
  byte_buffer_t *b;
801
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
802
+ pvt_put_cstring(b, string);
803
+ return self;
804
+ }
805
+
806
+ void pvt_put_cstring(byte_buffer_t *b, VALUE string)
807
+ {
360
808
  char *c_str = RSTRING_PTR(string);
361
809
  size_t length = RSTRING_LEN(string) + 1;
362
810
 
363
811
  if (!rb_bson_utf8_validate(c_str, length - 1, false)) {
364
812
  rb_raise(rb_eArgError, "String %s is not a valid UTF-8 CString.", c_str);
365
813
  }
366
-
367
- TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
368
814
  ENSURE_BSON_WRITE(b, length);
369
815
  memcpy(WRITE_PTR(b), c_str, length);
370
816
  b->write_position += length;
371
- return self;
817
+ }
818
+
819
+ /**
820
+ * Write a hash key to the byte buffer, validating it if requested
821
+ */
822
+ void pvt_put_bson_key(byte_buffer_t *b, VALUE string, VALUE validating_keys){
823
+ if(RTEST(validating_keys)){
824
+ char *c_str = RSTRING_PTR(string);
825
+ size_t length = RSTRING_LEN(string);
826
+ if(length > 0 && (c_str[0] == '$' || memchr(c_str, '.', length))){
827
+ rb_exc_raise(rb_funcall(rb_bson_illegal_key, rb_intern("new"),1, string));
828
+ }
829
+ }
830
+
831
+ pvt_put_cstring(b, string);
372
832
  }
373
833
 
374
834
  /**
@@ -398,13 +858,18 @@ VALUE rb_bson_byte_buffer_put_decimal128(VALUE self, VALUE low, VALUE high)
398
858
  VALUE rb_bson_byte_buffer_put_double(VALUE self, VALUE f)
399
859
  {
400
860
  byte_buffer_t *b;
401
- const double d = BSON_DOUBLE_TO_LE(NUM2DBL(f));
402
861
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
862
+ pvt_put_double(b,NUM2DBL(f));
863
+
864
+ return self;
865
+ }
866
+
867
+ void pvt_put_double(byte_buffer_t *b, double f)
868
+ {
869
+ const double d = BSON_DOUBLE_TO_LE(f);
403
870
  ENSURE_BSON_WRITE(b, 8);
404
871
  memcpy(WRITE_PTR(b), &d, 8);
405
872
  b->write_position += 8;
406
-
407
- return self;
408
873
  }
409
874
 
410
875
  /**
@@ -413,14 +878,19 @@ VALUE rb_bson_byte_buffer_put_double(VALUE self, VALUE f)
413
878
  VALUE rb_bson_byte_buffer_put_int32(VALUE self, VALUE i)
414
879
  {
415
880
  byte_buffer_t *b;
416
- const int32_t i32 = BSON_UINT32_TO_LE(NUM2INT(i));
881
+ const int32_t i32 = NUM2INT(i);
417
882
 
418
883
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
884
+ pvt_put_int32(b, i32);
885
+ return self;
886
+ }
887
+
888
+ void pvt_put_int32(byte_buffer_t *b, const int32_t i)
889
+ {
890
+ const int32_t i32 = BSON_UINT32_TO_LE(i);
419
891
  ENSURE_BSON_WRITE(b, 4);
420
892
  memcpy(WRITE_PTR(b), &i32, 4);
421
893
  b->write_position += 4;
422
-
423
- return self;
424
894
  }
425
895
 
426
896
  /**
@@ -429,14 +899,49 @@ VALUE rb_bson_byte_buffer_put_int32(VALUE self, VALUE i)
429
899
  VALUE rb_bson_byte_buffer_put_int64(VALUE self, VALUE i)
430
900
  {
431
901
  byte_buffer_t *b;
432
- const int64_t i64 = BSON_UINT64_TO_LE(NUM2LL(i));
902
+ const int64_t i64 = NUM2LL(i);
433
903
 
434
904
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
905
+ pvt_put_int64(b, i64);
906
+
907
+ return self;
908
+ }
909
+
910
+ void pvt_put_int64(byte_buffer_t *b, const int64_t i)
911
+ {
912
+ const int64_t i64 = BSON_UINT64_TO_LE(i);
913
+
435
914
  ENSURE_BSON_WRITE(b, 8);
436
915
  memcpy(WRITE_PTR(b), &i64, 8);
437
916
  b->write_position += 8;
438
917
 
439
- return self;
918
+ }
919
+
920
+ /**
921
+ * validate the buffer contains the amount of bytes the array / hash claimns
922
+ * and that it is null terminated
923
+ */
924
+ void pvt_validate_length(byte_buffer_t *b)
925
+ {
926
+ int32_t length;
927
+
928
+ ENSURE_BSON_READ(b, 4);
929
+ memcpy(&length, READ_PTR(b), 4);
930
+ length = BSON_UINT32_TO_LE(length);
931
+
932
+ /* minimum valid length is 4 (byte count) + 1 (terminating byte) */
933
+ if(length >= 5){
934
+ ENSURE_BSON_READ(b, length);
935
+
936
+ /* The last byte should be a null byte: it should be at length - 1 */
937
+ if( *(READ_PTR(b) + length - 1) != 0 ){
938
+ rb_raise(rb_eRangeError, "Buffer should have contained null terminator at %zu but contained %d", b->read_position + (size_t)length, (int)*(READ_PTR(b) + length));
939
+ }
940
+ b->read_position += 4;
941
+ }
942
+ else{
943
+ rb_raise(rb_eRangeError, "Buffer contained invalid length %d at %zu", length, b->read_position);
944
+ }
440
945
  }
441
946
 
442
947
  /**
@@ -481,16 +986,19 @@ VALUE rb_bson_byte_buffer_read_position(VALUE self)
481
986
  VALUE rb_bson_byte_buffer_replace_int32(VALUE self, VALUE index, VALUE i)
482
987
  {
483
988
  byte_buffer_t *b;
484
- const int32_t position = NUM2LONG(index);
485
- const int32_t i32 = BSON_UINT32_TO_LE(NUM2LONG(i));
486
989
 
487
990
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
488
-
489
- memcpy(READ_PTR(b) + position, &i32, 4);
991
+ pvt_replace_int32(b, NUM2LONG(index), NUM2LONG(i));
490
992
 
491
993
  return self;
492
994
  }
493
995
 
996
+ void pvt_replace_int32(byte_buffer_t *b, int32_t position, int32_t newval)
997
+ {
998
+ const int32_t i32 = BSON_UINT32_TO_LE(newval);
999
+ memcpy(READ_PTR(b) + position, &i32, 4);
1000
+ }
1001
+
494
1002
  /**
495
1003
  * Reset the read position to the beginning of the byte buffer.
496
1004
  */
data/lib/bson/array.rb CHANGED
@@ -41,15 +41,19 @@ module BSON
41
41
  #
42
42
  # @since 2.0.0
43
43
  def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
44
- position = buffer.length
45
- buffer.put_int32(0)
46
- each_with_index do |value, index|
47
- buffer.put_byte(value.bson_type)
48
- buffer.put_cstring(index.to_s)
49
- value.to_bson(buffer, validating_keys)
44
+ if buffer.respond_to?(:put_array)
45
+ buffer.put_array(self, validating_keys)
46
+ else
47
+ position = buffer.length
48
+ buffer.put_int32(0)
49
+ each_with_index do |value, index|
50
+ buffer.put_byte(value.bson_type)
51
+ buffer.put_cstring(index.to_s)
52
+ value.to_bson(buffer, validating_keys)
53
+ end
54
+ buffer.put_byte(NULL_BYTE)
55
+ buffer.replace_int32(position, buffer.length - position)
50
56
  end
51
- buffer.put_byte(NULL_BYTE)
52
- buffer.replace_int32(position, buffer.length - position)
53
57
  end
54
58
 
55
59
  # Convert the array to an object id. This will only work for arrays of size
@@ -93,13 +97,17 @@ module BSON
93
97
  #
94
98
  # @since 2.0.0
95
99
  def from_bson(buffer)
96
- array = new
97
- buffer.get_int32 # throw away the length
98
- while (type = buffer.get_byte) != NULL_BYTE
99
- buffer.get_cstring
100
- array << BSON::Registry.get(type).from_bson(buffer)
100
+ if buffer.respond_to?(:get_array)
101
+ buffer.get_array
102
+ else
103
+ array = new
104
+ buffer.get_int32 # throw away the length
105
+ while (type = buffer.get_byte) != NULL_BYTE
106
+ buffer.get_cstring
107
+ array << BSON::Registry.get(type).from_bson(buffer)
108
+ end
109
+ array
101
110
  end
102
- array
103
111
  end
104
112
  end
105
113
 
data/lib/bson/hash.rb CHANGED
@@ -38,15 +38,19 @@ module BSON
38
38
  #
39
39
  # @since 2.0.0
40
40
  def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
41
- position = buffer.length
42
- buffer.put_int32(0)
43
- each do |field, value|
44
- buffer.put_byte(value.bson_type)
45
- buffer.put_cstring(field.to_bson_key(validating_keys))
46
- value.to_bson(buffer, validating_keys)
41
+ if buffer.respond_to?(:put_hash)
42
+ buffer.put_hash(self, validating_keys)
43
+ else
44
+ position = buffer.length
45
+ buffer.put_int32(0)
46
+ each do |field, value|
47
+ buffer.put_byte(value.bson_type)
48
+ buffer.put_cstring(field.to_bson_key(validating_keys))
49
+ value.to_bson(buffer, validating_keys)
50
+ end
51
+ buffer.put_byte(NULL_BYTE)
52
+ buffer.replace_int32(position, buffer.length - position)
47
53
  end
48
- buffer.put_byte(NULL_BYTE)
49
- buffer.replace_int32(position, buffer.length - position)
50
54
  end
51
55
 
52
56
  # Converts the hash to a normalized value in a BSON document.
@@ -73,13 +77,17 @@ module BSON
73
77
  #
74
78
  # @since 2.0.0
75
79
  def from_bson(buffer)
76
- hash = Document.allocate
77
- buffer.get_int32 # Throw away the size.
78
- while (type = buffer.get_byte) != NULL_BYTE
79
- field = buffer.get_cstring
80
- hash.store(field, BSON::Registry.get(type, field).from_bson(buffer))
80
+ if buffer.respond_to?(:get_hash)
81
+ buffer.get_hash
82
+ else
83
+ hash = Document.allocate
84
+ buffer.get_int32 # Throw away the size.
85
+ while (type = buffer.get_byte) != NULL_BYTE
86
+ field = buffer.get_cstring
87
+ hash.store(field, BSON::Registry.get(type, field).from_bson(buffer))
88
+ end
89
+ hash
81
90
  end
82
- hash
83
91
  end
84
92
  end
85
93
 
data/lib/bson/registry.rb CHANGED
@@ -40,7 +40,7 @@ module BSON
40
40
  #
41
41
  # @since 2.0.0
42
42
  def get(byte, field = nil)
43
- if type = MAPPINGS[byte]
43
+ if type = MAPPINGS[byte] || (byte.is_a?(String) && type = MAPPINGS[byte.ord])
44
44
  type
45
45
  else
46
46
  handle_unsupported_type!(byte, field)
@@ -59,7 +59,7 @@ module BSON
59
59
  #
60
60
  # @since 2.0.0
61
61
  def register(byte, type)
62
- MAPPINGS.store(byte, type)
62
+ MAPPINGS[byte.ord] = type
63
63
  define_type_reader(type)
64
64
  end
65
65
 
data/lib/bson/symbol.rb CHANGED
@@ -105,7 +105,7 @@ module BSON
105
105
  # Register this type when the module is loaded.
106
106
  #
107
107
  # @since 2.0.0
108
- Registry::MAPPINGS.store(BSON_TYPE, ::Symbol)
108
+ Registry::MAPPINGS[BSON_TYPE.ord] = ::Symbol
109
109
  end
110
110
 
111
111
  # Enrich the core Symbol class with this module.
@@ -21,12 +21,18 @@ module BSON
21
21
  # @since 2.0.0
22
22
  class Timestamp
23
23
  include JSON
24
+ include Comparable
24
25
 
25
26
  # A timestamp is type 0x11 in the BSON spec.
26
27
  #
27
28
  # @since 2.0.0
28
29
  BSON_TYPE = 17.chr.force_encoding(BINARY).freeze
29
30
 
31
+ # Error message if an object other than a Timestamp is compared with this object.
32
+ #
33
+ # @since 4.3.0
34
+ COMPARISON_ERROR_MESSAGE = 'comparison of %s with Timestamp failed'.freeze
35
+
30
36
  # @!attribute seconds
31
37
  # @return [ Integer ] The number of seconds.
32
38
  # @since 2.0.0
@@ -52,6 +58,24 @@ module BSON
52
58
  seconds == other.seconds && increment == other.increment
53
59
  end
54
60
 
61
+ # Determine if this timestamp is greater or less than another object.
62
+ #
63
+ # @example Compare the timestamp.
64
+ # timestamp < other
65
+ #
66
+ # @param [ Object ] other The object to compare against.
67
+ #
68
+ # @return [ true, false ] The result of the comparison.
69
+ #
70
+ # @since 4.3.0
71
+ def <=>(other)
72
+ raise ArgumentError.new(COMPARISON_ERROR_MESSAGE % other.class) unless other.is_a?(Timestamp)
73
+ return 0 if self == other
74
+ a = [ seconds, increment ]
75
+ b = [ other.seconds, other.increment ]
76
+ [ a, b ].sort[0] == a ? -1 : 1
77
+ end
78
+
55
79
  # Get the timestamp as JSON hash data.
56
80
  #
57
81
  # @example Get the timestamp as a JSON hash.
data/lib/bson/version.rb CHANGED
@@ -13,5 +13,5 @@
13
13
  # limitations under the License.
14
14
 
15
15
  module BSON
16
- VERSION = "4.2.2".freeze
16
+ VERSION = "4.3.0.beta".freeze
17
17
  end
@@ -152,16 +152,30 @@ describe BSON::ByteBuffer do
152
152
 
153
153
  describe '#length' do
154
154
 
155
- let(:buffer) do
156
- described_class.new
157
- end
155
+ context 'when the byte buffer is initialized with no bytes' do
156
+
157
+ let(:buffer) do
158
+ described_class.new
159
+ end
160
+
161
+ before do
162
+ buffer.put_int32(5)
163
+ end
158
164
 
159
- before do
160
- buffer.put_int32(5)
165
+ it 'returns the length of the buffer' do
166
+ expect(buffer.length).to eq(4)
167
+ end
161
168
  end
162
169
 
163
- it 'returns the length of the buffer' do
164
- expect(buffer.length).to eq(4)
170
+ context 'when the byte buffer is initialized with some bytes' do
171
+
172
+ let(:buffer) do
173
+ described_class.new("#{BSON::Int32::BSON_TYPE}#{BSON::Int32::BSON_TYPE}")
174
+ end
175
+
176
+ it 'returns the length' do
177
+ expect(buffer.length).to eq(2)
178
+ end
165
179
  end
166
180
  end
167
181
 
@@ -756,6 +756,24 @@ describe BSON::Document do
756
756
  end
757
757
  end
758
758
 
759
+ context "when the hash contains an array of hashes" do
760
+ let(:obj) do
761
+ described_class["key",[{"a" => 1}, {"b" => 2}]]
762
+ end
763
+
764
+ let(:bson) do
765
+ "#{45.to_bson}#{Array::BSON_TYPE}key#{BSON::NULL_BYTE}" +
766
+ "#{35.to_bson}"+
767
+ "#{BSON::Document::BSON_TYPE}0#{BSON::NULL_BYTE}#{12.to_bson}#{BSON::Int32::BSON_TYPE}a#{BSON::NULL_BYTE}#{1.to_bson}#{BSON::NULL_BYTE}" +
768
+ "#{BSON::Document::BSON_TYPE}1#{BSON::NULL_BYTE}#{12.to_bson}#{BSON::Int32::BSON_TYPE}b#{BSON::NULL_BYTE}#{2.to_bson}#{BSON::NULL_BYTE}" +
769
+ "#{BSON::NULL_BYTE}" +
770
+ "#{BSON::NULL_BYTE}"
771
+ end
772
+
773
+ it_behaves_like "a serializable bson element"
774
+ it_behaves_like "a deserializable bson element"
775
+ end
776
+
759
777
  context "when the hash is a single level" do
760
778
 
761
779
  let(:obj) do
@@ -48,6 +48,61 @@ describe BSON::Timestamp do
48
48
  end
49
49
  end
50
50
 
51
+ describe "#<=>" do
52
+
53
+ let(:timestamp) do
54
+ described_class.new(1, 10)
55
+ end
56
+
57
+ context "when the objects are equal" do
58
+
59
+ let(:other) { described_class.new(1, 10) }
60
+
61
+ it "returns 0" do
62
+ expect(timestamp).to eq(other)
63
+ expect(timestamp < other).to be(false)
64
+ expect(timestamp > other).to be(false)
65
+ expect(timestamp >= other).to be(true)
66
+ expect(timestamp <= other).to be(true)
67
+ end
68
+ end
69
+
70
+ context "when the first object is less than the second" do
71
+
72
+ let(:other) { described_class.new(1, 15) }
73
+
74
+ it "returns -1" do
75
+ expect(timestamp <=> other).to be(-1)
76
+ expect(timestamp < other).to be(true)
77
+ expect(timestamp > other).to be(false)
78
+ expect(timestamp >= other).to be(false)
79
+ expect(timestamp <= other).to be(true)
80
+ end
81
+ end
82
+
83
+ context "when the first object is greater than the second" do
84
+
85
+ let(:other) { described_class.new(1, 5) }
86
+
87
+ it "returns 1" do
88
+ expect(timestamp <=> other).to be(1)
89
+ expect(timestamp < other).to be(false)
90
+ expect(timestamp > other).to be(true)
91
+ expect(timestamp >= other).to be(true)
92
+ expect(timestamp <= other).to be(false)
93
+ end
94
+ end
95
+
96
+ context "when the other object is not a timestamp" do
97
+
98
+ it "raises an ArgumentError" do
99
+ expect {
100
+ timestamp < 1
101
+ }.to raise_exception(ArgumentError)
102
+ end
103
+ end
104
+ end
105
+
51
106
  describe "#as_json" do
52
107
 
53
108
  let(:object) do
data/spec/spec_helper.rb CHANGED
@@ -24,6 +24,7 @@ require "bson"
24
24
  require "json"
25
25
  require "rspec"
26
26
  require "yaml"
27
+ require "pry-nav"
27
28
 
28
29
  Dir["./spec/support/**/*.rb"].each { |file| require file }
29
30
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bson
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.2
4
+ version: 4.3.0.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Brock
@@ -34,7 +34,7 @@ cert_chain:
34
34
  UgLdYyyGANc+TOKLFmx0eAJlCljAurbX7ctO2XI0f1AUdEYSqGzut+datXK/9nwQ
35
35
  FACf8zd11PEds/Opai2Qp4aOBgaxXhhFG357umy1vRs=
36
36
  -----END CERTIFICATE-----
37
- date: 2017-07-03 00:00:00.000000000 Z
37
+ date: 2017-09-20 00:00:00.000000000 Z
38
38
  dependencies: []
39
39
  description: A full featured BSON specification implementation, in Ruby
40
40
  email:
metadata.gz.sig CHANGED
Binary file