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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ext/bson/bson_native.c +527 -19
- data/lib/bson/array.rb +22 -14
- data/lib/bson/hash.rb +22 -14
- data/lib/bson/registry.rb +2 -2
- data/lib/bson/symbol.rb +1 -1
- data/lib/bson/timestamp.rb +24 -0
- data/lib/bson/version.rb +1 -1
- data/spec/bson/byte_buffer_spec.rb +21 -7
- data/spec/bson/document_spec.rb +18 -0
- data/spec/bson/timestamp_spec.rb +55 -0
- data/spec/spec_helper.rb +1 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a8c878410e043f1b920f996932401686eb2ef59
|
4
|
+
data.tar.gz: e459f34a04cbc3cc71f4723e95225fc69af98796
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0ba9d2a810a8dd77520b0605b351dfc9c06525dab2998f77755480e1600a2d799dd6ca2084268a903e335e4336b6c96a829c2943cc2f7adeea55ee8b1bf1f15
|
7
|
+
data.tar.gz: 54c0d9e149895d20f857273a392d4895b55c61f2642d5c6561a0ce2478707f56a0bf810c8ea5220a1fbdf1b69d59f6ce0ced391cbd00e7dd4f8b25ade6418d6d
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/ext/bson/bson_native.c
CHANGED
@@ -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
|
-
|
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 =
|
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 =
|
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
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
buffer.
|
48
|
-
buffer.
|
49
|
-
value
|
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
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
buffer.
|
45
|
-
buffer.
|
46
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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.
|
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.
|
108
|
+
Registry::MAPPINGS[BSON_TYPE.ord] = ::Symbol
|
109
109
|
end
|
110
110
|
|
111
111
|
# Enrich the core Symbol class with this module.
|
data/lib/bson/timestamp.rb
CHANGED
@@ -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
@@ -152,16 +152,30 @@ describe BSON::ByteBuffer do
|
|
152
152
|
|
153
153
|
describe '#length' do
|
154
154
|
|
155
|
-
|
156
|
-
|
157
|
-
|
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
|
-
|
160
|
-
|
165
|
+
it 'returns the length of the buffer' do
|
166
|
+
expect(buffer.length).to eq(4)
|
167
|
+
end
|
161
168
|
end
|
162
169
|
|
163
|
-
|
164
|
-
|
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
|
|
data/spec/bson/document_spec.rb
CHANGED
@@ -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
|
data/spec/bson/timestamp_spec.rb
CHANGED
@@ -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
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.
|
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-
|
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
|