bson 4.2.2 → 4.3.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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