bson 4.7.1 → 4.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -2
  3. data.tar.gz.sig +0 -0
  4. data/README.md +5 -1
  5. data/ext/bson/bson-native.h +14 -4
  6. data/ext/bson/init.c +25 -2
  7. data/ext/bson/read.c +61 -15
  8. data/ext/bson/util.c +40 -0
  9. data/ext/bson/write.c +17 -13
  10. data/lib/bson.rb +3 -0
  11. data/lib/bson/array.rb +21 -3
  12. data/lib/bson/binary.rb +41 -3
  13. data/lib/bson/boolean.rb +3 -1
  14. data/lib/bson/code.rb +15 -1
  15. data/lib/bson/code_with_scope.rb +17 -3
  16. data/lib/bson/db_pointer.rb +104 -0
  17. data/lib/bson/decimal128.rb +15 -1
  18. data/lib/bson/error.rb +17 -0
  19. data/lib/bson/ext_json.rb +374 -0
  20. data/lib/bson/float.rb +47 -1
  21. data/lib/bson/hash.rb +23 -3
  22. data/lib/bson/int32.rb +21 -1
  23. data/lib/bson/int64.rb +28 -3
  24. data/lib/bson/integer.rb +34 -0
  25. data/lib/bson/max_key.rb +12 -0
  26. data/lib/bson/min_key.rb +12 -0
  27. data/lib/bson/nil_class.rb +3 -1
  28. data/lib/bson/object.rb +27 -0
  29. data/lib/bson/object_id.rb +15 -1
  30. data/lib/bson/regexp.rb +19 -2
  31. data/lib/bson/specialized.rb +3 -1
  32. data/lib/bson/string.rb +3 -1
  33. data/lib/bson/symbol.rb +92 -3
  34. data/lib/bson/time.rb +28 -3
  35. data/lib/bson/timestamp.rb +15 -1
  36. data/lib/bson/undefined.rb +11 -0
  37. data/lib/bson/version.rb +1 -1
  38. data/spec/bson/binary_spec.rb +33 -3
  39. data/spec/bson/ext_json_parse_spec.rb +276 -0
  40. data/spec/bson/float_spec.rb +36 -0
  41. data/spec/bson/hash_spec.rb +70 -0
  42. data/spec/bson/int32_spec.rb +20 -0
  43. data/spec/bson/int64_spec.rb +38 -0
  44. data/spec/bson/integer_spec.rb +26 -0
  45. data/spec/bson/raw_spec.rb +22 -1
  46. data/spec/bson/symbol_raw_spec.rb +45 -0
  47. data/spec/bson/symbol_spec.rb +60 -0
  48. data/spec/{support → runners}/common_driver.rb +0 -0
  49. data/spec/runners/corpus.rb +182 -0
  50. data/spec/{support/corpus.rb → runners/corpus_legacy.rb} +40 -58
  51. data/spec/spec_helper.rb +9 -2
  52. data/spec/{bson/driver_bson_spec.rb → spec_tests/common_driver_spec.rb} +1 -0
  53. data/spec/{bson/corpus_spec.rb → spec_tests/corpus_legacy_spec.rb} +4 -4
  54. data/spec/spec_tests/corpus_spec.rb +124 -0
  55. data/spec/spec_tests/data/corpus/README.md +15 -0
  56. data/spec/spec_tests/data/corpus/array.json +49 -0
  57. data/spec/spec_tests/data/corpus/binary.json +85 -0
  58. data/spec/spec_tests/data/corpus/boolean.json +27 -0
  59. data/spec/spec_tests/data/corpus/code.json +67 -0
  60. data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
  61. data/spec/spec_tests/data/corpus/datetime.json +42 -0
  62. data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
  63. data/spec/spec_tests/data/corpus/dbref.json +31 -0
  64. data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
  65. data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
  66. data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
  67. data/spec/spec_tests/data/corpus/decimal128-4.json +117 -0
  68. data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
  69. data/spec/spec_tests/data/corpus/decimal128-6.json +119 -0
  70. data/spec/spec_tests/data/corpus/decimal128-7.json +323 -0
  71. data/spec/spec_tests/data/corpus/document.json +36 -0
  72. data/spec/spec_tests/data/corpus/double.json +87 -0
  73. data/spec/spec_tests/data/corpus/int32.json +43 -0
  74. data/spec/spec_tests/data/corpus/int64.json +43 -0
  75. data/spec/spec_tests/data/corpus/maxkey.json +12 -0
  76. data/spec/spec_tests/data/corpus/minkey.json +12 -0
  77. data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
  78. data/spec/spec_tests/data/corpus/multi-type.json +11 -0
  79. data/spec/spec_tests/data/corpus/null.json +12 -0
  80. data/spec/spec_tests/data/corpus/oid.json +28 -0
  81. data/spec/spec_tests/data/corpus/regex.json +65 -0
  82. data/spec/spec_tests/data/corpus/string.json +72 -0
  83. data/spec/spec_tests/data/corpus/symbol.json +80 -0
  84. data/spec/spec_tests/data/corpus/timestamp.json +24 -0
  85. data/spec/spec_tests/data/corpus/top.json +240 -0
  86. data/spec/spec_tests/data/corpus/undefined.json +15 -0
  87. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/array.json +0 -0
  88. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/binary.json +0 -0
  89. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/boolean.json +0 -0
  90. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code.json +1 -1
  91. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code_w_scope.json +1 -1
  92. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/document.json +1 -1
  93. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/double.json +1 -1
  94. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/datetime.json +0 -0
  95. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/dbpointer.json +0 -0
  96. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/int64.json +0 -0
  97. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/symbol.json +0 -0
  98. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/int32.json +1 -1
  99. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/maxkey.json +1 -1
  100. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/minkey.json +1 -1
  101. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/null.json +1 -1
  102. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/oid.json +0 -0
  103. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/regex.json +1 -1
  104. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/string.json +0 -0
  105. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/timestamp.json +1 -1
  106. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/top.json +0 -0
  107. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/undefined.json +0 -0
  108. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-1.json +0 -0
  109. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-2.json +0 -0
  110. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-3.json +0 -0
  111. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-4.json +0 -0
  112. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-5.json +0 -0
  113. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-6.json +0 -0
  114. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-7.json +0 -0
  115. metadata +170 -95
  116. metadata.gz.sig +2 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8a3b9746ff3d1a260ea84b199e2d0f5633dd64a2f35cd0b25f5c6e04fe7087d
4
- data.tar.gz: cfa985f7f17d689484240c54756b3a0248f0a8c97573cbfc1af0fbc037835e3d
3
+ metadata.gz: c37081fa823c2700f07a23ca6ecbec6fc67cffbf7915b4a21e59940b332b678d
4
+ data.tar.gz: 16d483a311c4252f4ef1463be2f86240450b82294a972d8bb5bb2bb332fd7b17
5
5
  SHA512:
6
- metadata.gz: bde5c1c92fd57f6e9ed5ad0cec9957521949022141a98a7fd47c551cdb313380c56607dd6946575cbfe20413170ff009cb6d8d165f674ed3f82e7ce63576c8e9
7
- data.tar.gz: c857d6e12472340748ebb2c31da5ddc637510fbf07248d4a8ce9277967acfd74bca0bb065cbc1369c75e14d1994fa099ce8a40c4e468003376b92304a7883029
6
+ metadata.gz: 1618b74348d155c904b2f24739d7b9403bc0b1c23e67cc6ce89a92ac19070dd5965dc1fccc6353c2eefb82993bf5fec30702bccaaf6bb8171777421253832cce
7
+ data.tar.gz: 1362710c9b36348437bf266a52c18347c1228ddd92231b520e6b068b1742f42895c2108a64cdff2487c5b874c12e3af5ce4d4435c00cebad942b83f1ea9e17ab
@@ -1,2 +1,2 @@
1
- �}( v�+�͎z�5�s�n�:���@�;�vL��Y��<T���BE8$�n�O;�@��y�y��ۆ�\#�;+9�S#r���A���\~JdJt��X �&H�R/j`U��.����Ռ=���W&W��������$l������C�b>gCՍ]P���Ԓ&�M�K& [��,�6�+V��+��Z֦�iE62~���S��hQ�Sd���v���}�f������/"�'
2
- ��)�Ɏ I��
1
+ �}
2
+ O��t���9�a���2)����=%Zf{ms 3VeB�L)¡o�crp �e��r��@�K�~�
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -1,4 +1,8 @@
1
- BSON [![Build Status](https://secure.travis-ci.org/mongodb/bson-ruby.png?branch=master&.png)](http://travis-ci.org/mongodb/bson-ruby) [![Code Climate](https://codeclimate.com/github/mongodb/bson-ruby.png)](https://codeclimate.com/github/mongodb/bson-ruby) [![Coverage Status](https://coveralls.io/repos/mongodb/bson-ruby/badge.png?branch=master)](https://coveralls.io/r/mongodb/bson-ruby?branch=master) [![Inline docs](http://inch-ci.org/github/mongodb/bson-ruby.svg?branch=master)](http://inch-ci.org/github/mongodb/bson-ruby)
1
+ BSON [![Build Status](https://secure.travis-ci.org/mongodb/bson-ruby.svg?branch=master)](http://travis-ci.org/mongodb/bson-ruby)
2
+ [![Build status Windows](https://ci.appveyor.com/api/projects/status/p5aqko7umsx351nm?svg=true)](https://ci.appveyor.com/project/p-mongo/bson-ruby/branch/master)
3
+ [![Code Climate](https://codeclimate.com/github/mongodb/bson-ruby.svg)](https://codeclimate.com/github/mongodb/bson-ruby)
4
+ [![Coverage Status](https://coveralls.io/repos/mongodb/bson-ruby/badge.svg?branch=master)](https://coveralls.io/r/mongodb/bson-ruby?branch=master)
5
+ [![Inline docs](http://inch-ci.org/github/mongodb/bson-ruby.svg?branch=master)](http://inch-ci.org/github/mongodb/bson-ruby)
2
6
  ====
3
7
 
4
8
  An implementation of the BSON specification in Ruby.
@@ -33,13 +33,15 @@ rb_bson_utf8_validate (const char *utf8, /* IN */
33
33
  #define HOST_NAME_HASH_MAX 256
34
34
  #endif
35
35
 
36
+ /* See the type list in http://bsonspec.org/spec.html. */
36
37
  #define BSON_TYPE_DOUBLE 1
37
38
  #define BSON_TYPE_STRING 2
38
39
  #define BSON_TYPE_DOCUMENT 3
39
40
  #define BSON_TYPE_ARRAY 4
40
41
  #define BSON_TYPE_BOOLEAN 8
41
- #define BSON_TYPE_INT32 16
42
- #define BSON_TYPE_INT64 18
42
+ #define BSON_TYPE_SYMBOL 0x0E
43
+ #define BSON_TYPE_INT32 0x10
44
+ #define BSON_TYPE_INT64 0x12
43
45
 
44
46
  typedef struct {
45
47
  size_t size;
@@ -76,8 +78,8 @@ VALUE rb_bson_byte_buffer_get_double(VALUE self);
76
78
  VALUE rb_bson_byte_buffer_get_int32(VALUE self);
77
79
  VALUE rb_bson_byte_buffer_get_int64(VALUE self);
78
80
  VALUE rb_bson_byte_buffer_get_string(VALUE self);
79
- VALUE rb_bson_byte_buffer_get_hash(VALUE self);
80
- VALUE rb_bson_byte_buffer_get_array(VALUE self);
81
+ VALUE rb_bson_byte_buffer_get_hash(int argc, VALUE *argv, VALUE self);
82
+ VALUE rb_bson_byte_buffer_get_array(int argc, VALUE *argv, VALUE self);
81
83
  VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte);
82
84
  VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes);
83
85
  VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE string);
@@ -101,6 +103,14 @@ void rb_bson_byte_buffer_free(void *ptr);
101
103
  void rb_bson_expand_buffer(byte_buffer_t* buffer_ptr, size_t length);
102
104
  void rb_bson_generate_machine_id(VALUE rb_md5_class, char *rb_bson_machine_id);
103
105
 
106
+ VALUE pvt_const_get_2(const char *c1, const char *c2);
107
+ VALUE pvt_const_get_3(const char *c1, const char *c2, const char *c3);
108
+
109
+ #define BSON_MODE_DEFAULT 0
110
+ #define BSON_MODE_BSON 1
111
+
112
+ int pvt_get_mode_option(int argc, VALUE *argv);
113
+
104
114
  /**
105
115
  * The counter for incrementing object ids.
106
116
  */
@@ -70,8 +70,31 @@ void Init_bson_native()
70
70
  rb_define_method(rb_byte_buffer_class, "get_cstring", rb_bson_byte_buffer_get_cstring, 0);
71
71
  rb_define_method(rb_byte_buffer_class, "get_decimal128_bytes", rb_bson_byte_buffer_get_decimal128_bytes, 0);
72
72
  rb_define_method(rb_byte_buffer_class, "get_double", rb_bson_byte_buffer_get_double, 0);
73
- rb_define_method(rb_byte_buffer_class, "get_hash", rb_bson_byte_buffer_get_hash, 0);
74
- rb_define_method(rb_byte_buffer_class, "get_array", rb_bson_byte_buffer_get_array, 0);
73
+
74
+ /*
75
+ * call-seq:
76
+ * buffer.get_hash(**options) -> Hash
77
+ *
78
+ * Reads a document from the byte buffer and returns it as a BSON::Document.
79
+ *
80
+ * @option options [ nil | :bson ] :mode Decoding mode to use.
81
+ *
82
+ * @return [ BSON::Document ] The decoded document.
83
+ */
84
+ rb_define_method(rb_byte_buffer_class, "get_hash", rb_bson_byte_buffer_get_hash, -1);
85
+
86
+ /*
87
+ * call-seq:
88
+ * buffer.get_array(**options) -> Array
89
+ *
90
+ * Reads an array from the byte buffer..
91
+ *
92
+ * @option options [ nil | :bson ] :mode Decoding mode to use.
93
+ *
94
+ * @return [ Array ] The decoded array.
95
+ */
96
+ rb_define_method(rb_byte_buffer_class, "get_array", rb_bson_byte_buffer_get_array, -1);
97
+
75
98
  rb_define_method(rb_byte_buffer_class, "get_int32", rb_bson_byte_buffer_get_int32, 0);
76
99
  rb_define_method(rb_byte_buffer_class, "get_int64", rb_bson_byte_buffer_get_int64, 0);
77
100
  rb_define_method(rb_byte_buffer_class, "get_string", rb_bson_byte_buffer_get_string, 0);
@@ -20,11 +20,12 @@
20
20
  static void pvt_validate_length(byte_buffer_t *b);
21
21
  static uint8_t pvt_get_type_byte(byte_buffer_t *b);
22
22
  static VALUE pvt_get_int32(byte_buffer_t *b);
23
- static VALUE pvt_get_int64(byte_buffer_t *b);
23
+ static VALUE pvt_get_int64(byte_buffer_t *b, int argc, VALUE *argv);
24
24
  static VALUE pvt_get_double(byte_buffer_t *b);
25
25
  static VALUE pvt_get_string(byte_buffer_t *b);
26
+ static VALUE pvt_get_symbol(byte_buffer_t *b, VALUE rb_buffer, int argc, VALUE *argv);
26
27
  static VALUE pvt_get_boolean(byte_buffer_t *b);
27
- static VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type);
28
+ static VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type, int argc, VALUE *argv);
28
29
  static void pvt_skip_cstring(byte_buffer_t *b);
29
30
 
30
31
  /**
@@ -57,14 +58,16 @@ void pvt_validate_length(byte_buffer_t *b)
57
58
  /**
58
59
  * Read a single field from a hash or array
59
60
  */
60
- VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type){
61
+ VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type, int argc, VALUE *argv)
62
+ {
61
63
  switch(type) {
62
64
  case BSON_TYPE_INT32: return pvt_get_int32(b);
63
- case BSON_TYPE_INT64: return pvt_get_int64(b);
65
+ case BSON_TYPE_INT64: return pvt_get_int64(b, argc, argv);
64
66
  case BSON_TYPE_DOUBLE: return pvt_get_double(b);
65
67
  case BSON_TYPE_STRING: return pvt_get_string(b);
66
- case BSON_TYPE_ARRAY: return rb_bson_byte_buffer_get_array(rb_buffer);
67
- case BSON_TYPE_DOCUMENT: return rb_bson_byte_buffer_get_hash(rb_buffer);
68
+ case BSON_TYPE_SYMBOL: return pvt_get_symbol(b, rb_buffer, argc, argv);
69
+ case BSON_TYPE_ARRAY: return rb_bson_byte_buffer_get_array(argc, argv, rb_buffer);
70
+ case BSON_TYPE_DOCUMENT: return rb_bson_byte_buffer_get_hash(argc, argv, rb_buffer);
68
71
  case BSON_TYPE_BOOLEAN: return pvt_get_boolean(b);
69
72
  default:
70
73
  {
@@ -150,6 +153,31 @@ VALUE pvt_get_string(byte_buffer_t *b)
150
153
  return string;
151
154
  }
152
155
 
156
+ /**
157
+ * Reads a UTF-8 string out of the byte buffer. If the argc/argv arguments
158
+ * have a :mode option with the value of :bson, wraps the string in a
159
+ * BSON::Symbol::Raw. Otherwise consults the BSON registry to determine
160
+ * which class to instantiate (String in bson-ruby, overridden to Symbol by
161
+ * the Ruby driver). Returns either a BSON::Symbol::Raw, Symbol or String
162
+ * value.
163
+ */
164
+ VALUE pvt_get_symbol(byte_buffer_t *b, VALUE rb_buffer, int argc, VALUE *argv)
165
+ {
166
+ VALUE value, klass;
167
+
168
+ if (pvt_get_mode_option(argc, argv) == BSON_MODE_BSON) {
169
+ value = pvt_get_string(b);
170
+ klass = pvt_const_get_3("BSON", "Symbol", "Raw");
171
+ value = rb_funcall(klass, rb_intern("new"), 1, value);
172
+ } else {
173
+ klass = rb_funcall(rb_bson_registry, rb_intern("get"), 1, INT2FIX(BSON_TYPE_SYMBOL));
174
+ value = rb_funcall(klass, rb_intern("from_bson"), 1, rb_buffer);
175
+ }
176
+
177
+ RB_GC_GUARD(klass);
178
+ return value;
179
+ }
180
+
153
181
  /**
154
182
  * Get a cstring from the buffer.
155
183
  */
@@ -206,17 +234,35 @@ VALUE rb_bson_byte_buffer_get_int64(VALUE self)
206
234
  {
207
235
  byte_buffer_t *b;
208
236
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
209
- return pvt_get_int64(b);
237
+ return pvt_get_int64(b, 0, NULL);
210
238
  }
211
239
 
212
- VALUE pvt_get_int64(byte_buffer_t *b)
240
+ /**
241
+ * Reads a 64-bit integer out of the byte buffer into a Ruby Integer instance.
242
+ * If the argc/argv arguments have a :mode option with the value of :bson,
243
+ * wraps the integer in a BSON::Int64. Returns either the Integer or the
244
+ * BSON::Int64 instance.
245
+ */
246
+ VALUE pvt_get_int64(byte_buffer_t *b, int argc, VALUE *argv)
213
247
  {
214
248
  int64_t i64;
249
+ VALUE num;
215
250
 
216
251
  ENSURE_BSON_READ(b, 8);
217
252
  memcpy(&i64, READ_PTR(b), 8);
218
253
  b->read_position += 8;
219
- return LL2NUM(BSON_UINT64_FROM_LE(i64));
254
+ num = LL2NUM(BSON_UINT64_FROM_LE(i64));
255
+
256
+ if (pvt_get_mode_option(argc, argv) == BSON_MODE_BSON) {
257
+ VALUE klass = rb_funcall(rb_bson_registry,rb_intern("get"),1, INT2FIX(BSON_TYPE_INT64));
258
+ VALUE value = rb_funcall(klass, rb_intern("new"), 1, num);
259
+ RB_GC_GUARD(klass);
260
+ return value;
261
+ } else {
262
+ return num;
263
+ }
264
+
265
+ RB_GC_GUARD(num);
220
266
  }
221
267
 
222
268
  /**
@@ -255,27 +301,27 @@ VALUE rb_bson_byte_buffer_get_decimal128_bytes(VALUE self)
255
301
  return bytes;
256
302
  }
257
303
 
258
- VALUE rb_bson_byte_buffer_get_hash(VALUE self){
304
+ VALUE rb_bson_byte_buffer_get_hash(int argc, VALUE *argv, VALUE self){
259
305
  VALUE doc = Qnil;
260
306
  byte_buffer_t *b = NULL;
261
307
  uint8_t type;
262
- VALUE cDocument = rb_const_get(rb_const_get(rb_cObject, rb_intern("BSON")), rb_intern("Document"));
308
+ VALUE cDocument = pvt_const_get_2("BSON", "Document");
263
309
 
264
310
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
265
311
 
266
312
  pvt_validate_length(b);
267
313
 
268
- doc = rb_funcall(cDocument, rb_intern("allocate"),0);
314
+ doc = rb_funcall(cDocument, rb_intern("allocate"), 0);
269
315
 
270
316
  while((type = pvt_get_type_byte(b)) != 0){
271
317
  VALUE field = rb_bson_byte_buffer_get_cstring(self);
318
+ rb_hash_aset(doc, field, pvt_read_field(b, self, type, argc, argv));
272
319
  RB_GC_GUARD(field);
273
- rb_hash_aset(doc, field, pvt_read_field(b, self, type));
274
320
  }
275
321
  return doc;
276
322
  }
277
323
 
278
- VALUE rb_bson_byte_buffer_get_array(VALUE self){
324
+ VALUE rb_bson_byte_buffer_get_array(int argc, VALUE *argv, VALUE self){
279
325
  byte_buffer_t *b;
280
326
  VALUE array = Qnil;
281
327
  uint8_t type;
@@ -287,7 +333,7 @@ VALUE rb_bson_byte_buffer_get_array(VALUE self){
287
333
  array = rb_ary_new();
288
334
  while((type = pvt_get_type_byte(b)) != 0){
289
335
  pvt_skip_cstring(b);
290
- rb_ary_push(array, pvt_read_field(b, self, type));
336
+ rb_ary_push(array, pvt_read_field(b, self, type, argc, argv));
291
337
  }
292
338
  RB_GC_GUARD(array);
293
339
  return array;
@@ -53,3 +53,43 @@ VALUE rb_bson_object_id_generator_next(int argc, VALUE* args, VALUE self)
53
53
  rb_bson_object_id_counter++;
54
54
  return rb_str_new(bytes, 12);
55
55
  }
56
+
57
+ /**
58
+ * Returns a Ruby constant nested one level, e.g. BSON::Document.
59
+ */
60
+ VALUE pvt_const_get_2(const char *c1, const char *c2) {
61
+ return rb_const_get(rb_const_get(rb_cObject, rb_intern(c1)), rb_intern(c2));
62
+ }
63
+
64
+ /**
65
+ * Returns a Ruby constant nested two levels, e.g. BSON::Regexp::Raw.
66
+ */
67
+ VALUE pvt_const_get_3(const char *c1, const char *c2, const char *c3) {
68
+ return rb_const_get(pvt_const_get_2(c1, c2), rb_intern(c3));
69
+ }
70
+
71
+ /**
72
+ * Returns the value of the :mode option, or the default if the option is not
73
+ * specified. Raises ArgumentError if the value is not one of nil or :bson.
74
+ * A future version of bson-ruby is expected to also support :ruby and :ruby!
75
+ * values. Returns one of the BSON_MODE_* values.
76
+ */
77
+ int pvt_get_mode_option(int argc, VALUE *argv) {
78
+ VALUE opts;
79
+ VALUE mode;
80
+
81
+ rb_scan_args(argc, argv, ":", &opts);
82
+ if (NIL_P(opts)) {
83
+ return BSON_MODE_DEFAULT;
84
+ } else {
85
+ mode = rb_hash_lookup(opts, ID2SYM(rb_intern("mode")));
86
+ if (mode == Qnil) {
87
+ return BSON_MODE_DEFAULT;
88
+ } else if (mode == ID2SYM(rb_intern("bson"))) {
89
+ return BSON_MODE_BSON;
90
+ } else {
91
+ rb_raise(rb_eArgError, "Invalid value for :mode option: %s",
92
+ RSTRING_PTR(rb_funcall(mode, rb_intern("inspect"), 0)));
93
+ }
94
+ }
95
+ }
@@ -125,40 +125,44 @@ VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes)
125
125
  return self;
126
126
  }
127
127
 
128
- /* write the byte denoting the BSON type for the passed object*/
128
+ /* write the byte denoting the BSON type for the passed object */
129
129
  void pvt_put_type_byte(byte_buffer_t *b, VALUE val){
130
- switch(TYPE(val)){
130
+ char type_byte;
131
+
132
+ switch (TYPE(val)){
131
133
  case T_BIGNUM:
132
134
  case T_FIXNUM:
133
- if(fits_int32(NUM2LL(val))){
134
- pvt_put_byte(b, BSON_TYPE_INT32);
135
- }else{
136
- pvt_put_byte(b, BSON_TYPE_INT64);
135
+ if (fits_int32(NUM2LL(val))) {
136
+ type_byte = BSON_TYPE_INT32;
137
+ } else {
138
+ type_byte = BSON_TYPE_INT64;
137
139
  }
138
140
  break;
139
141
  case T_STRING:
140
- pvt_put_byte(b, BSON_TYPE_STRING);
142
+ type_byte = BSON_TYPE_STRING;
141
143
  break;
142
144
  case T_ARRAY:
143
- pvt_put_byte(b, BSON_TYPE_ARRAY);
145
+ type_byte = BSON_TYPE_ARRAY;
144
146
  break;
145
147
  case T_TRUE:
146
148
  case T_FALSE:
147
- pvt_put_byte(b, BSON_TYPE_BOOLEAN);
149
+ type_byte = BSON_TYPE_BOOLEAN;
148
150
  break;
149
151
  case T_HASH:
150
- pvt_put_byte(b, BSON_TYPE_DOCUMENT);
152
+ type_byte = BSON_TYPE_DOCUMENT;
151
153
  break;
152
154
  case T_FLOAT:
153
- pvt_put_byte(b, BSON_TYPE_DOUBLE);
155
+ type_byte = BSON_TYPE_DOUBLE;
154
156
  break;
155
157
  default:{
156
- VALUE type = rb_funcall(val, rb_intern("bson_type"),0);
158
+ VALUE type = rb_funcall(val, rb_intern("bson_type"), 0);
159
+ type_byte = *RSTRING_PTR(type);
157
160
  RB_GC_GUARD(type);
158
- pvt_put_byte(b, *RSTRING_PTR(type));
159
161
  break;
160
162
  }
161
163
  }
164
+
165
+ pvt_put_byte(b, type_byte);
162
166
  }
163
167
 
164
168
  /**
@@ -57,6 +57,7 @@ module BSON
57
57
  end
58
58
 
59
59
  require "bson/config"
60
+ require "bson/error"
60
61
  require "bson/registry"
61
62
  require "bson/specialized"
62
63
  require "bson/json"
@@ -70,8 +71,10 @@ require "bson/code"
70
71
  require "bson/code_with_scope"
71
72
  require "bson/date"
72
73
  require "bson/date_time"
74
+ require "bson/db_pointer"
73
75
  require "bson/decimal128"
74
76
  require "bson/document"
77
+ require "bson/ext_json"
75
78
  require "bson/false_class"
76
79
  require "bson/float"
77
80
  require "bson/hash"
@@ -85,26 +85,44 @@ module BSON
85
85
  map { |value| value.to_bson_normalized_value }
86
86
  end
87
87
 
88
+ # Converts this object to a representation directly serializable to
89
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
90
+ #
91
+ # This method recursively invokes +as_extended_json+ with the provided
92
+ # options on each array element.
93
+ #
94
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
95
+ # (default is canonical extended JSON)
96
+ #
97
+ # @return [ Array ] This array converted to extended json representation.
98
+ def as_extended_json(**options)
99
+ map do |item|
100
+ item.as_extended_json(**options)
101
+ end
102
+ end
103
+
88
104
  module ClassMethods
89
105
 
90
106
  # Deserialize the array from BSON.
91
107
  #
92
108
  # @param [ ByteBuffer ] buffer The byte buffer.
93
109
  #
110
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
111
+ #
94
112
  # @return [ Array ] The decoded array.
95
113
  #
96
114
  # @see http://bsonspec.org/#/specification
97
115
  #
98
116
  # @since 2.0.0
99
- def from_bson(buffer)
117
+ def from_bson(buffer, **options)
100
118
  if buffer.respond_to?(:get_array)
101
- buffer.get_array
119
+ buffer.get_array(**options)
102
120
  else
103
121
  array = new
104
122
  buffer.get_int32 # throw away the length
105
123
  while (type = buffer.get_byte) != NULL_BYTE
106
124
  buffer.get_cstring
107
- array << BSON::Registry.get(type).from_bson(buffer)
125
+ array << BSON::Registry.get(type).from_bson(buffer, **options)
108
126
  end
109
127
  array
110
128
  end
@@ -31,6 +31,12 @@ module BSON
31
31
 
32
32
  # The mappings of subtypes to their single byte identifiers.
33
33
  #
34
+ # @note subtype 6 (ciphertext) is used for the Client-Side Encryption
35
+ # feature. Data represented by this subtype is often encrypted, but
36
+ # may also be plaintext. All instances of this subtype necessary for
37
+ # Client-Side Encryption will be created internally by the Ruby driver.
38
+ # An application should not create new BSON::Binary objects of this subtype.
39
+ #
34
40
  # @since 2.0.0
35
41
  SUBTYPES = {
36
42
  :generic => 0.chr,
@@ -39,6 +45,7 @@ module BSON
39
45
  :uuid_old => 3.chr,
40
46
  :uuid => 4.chr,
41
47
  :md5 => 5.chr,
48
+ :ciphertext => 6.chr,
42
49
  :user => 128.chr
43
50
  }.freeze
44
51
 
@@ -94,8 +101,31 @@ module BSON
94
101
  # @return [ Hash ] The binary as a JSON hash.
95
102
  #
96
103
  # @since 2.0.0
104
+ # @deprecated Use as_extended_json instead.
97
105
  def as_json(*args)
98
- { "$binary" => Base64.encode64(data), "$type" => type }
106
+ as_extended_json
107
+ end
108
+
109
+ # Converts this object to a representation directly serializable to
110
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
111
+ #
112
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
113
+ # (default is canonical extended JSON)
114
+ #
115
+ # @return [ Hash ] The extended json representation.
116
+ def as_extended_json(**options)
117
+ subtype = SUBTYPES[type].each_byte.map { |c| c.to_s(16) }.join
118
+ if subtype.length == 1
119
+ subtype = "0#{subtype}"
120
+ end
121
+
122
+ value = Base64.encode64(data).strip
123
+
124
+ if options[:mode] == :legacy
125
+ { "$binary" => value, "$type" => subtype }
126
+ else
127
+ { "$binary" => {'base64' => value, "subType" => subtype }}
128
+ end
99
129
  end
100
130
 
101
131
  # Instantiate the new binary object.
@@ -228,14 +258,22 @@ module BSON
228
258
  #
229
259
  # @param [ ByteBuffer ] buffer The byte buffer.
230
260
  #
261
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
262
+ #
231
263
  # @return [ Binary ] The decoded binary data.
232
264
  #
233
265
  # @see http://bsonspec.org/#/specification
234
266
  #
235
267
  # @since 2.0.0
236
- def self.from_bson(buffer)
268
+ def self.from_bson(buffer, **options)
237
269
  length = buffer.get_int32
238
- type = TYPES[buffer.get_byte]
270
+ type_byte = buffer.get_byte
271
+ type = TYPES[type_byte]
272
+ if type.nil?
273
+ raise Error::UnsupportedBinarySubtype,
274
+ "BSON data contains unsupported binary subtype #{'0x%02x' % type_byte.ord}"
275
+ end
276
+
239
277
  length = buffer.get_int32 if type == :old
240
278
  data = buffer.get_bytes(length)
241
279
  new(data, type)