msgpack 1.2.10 → 1.5.1

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +57 -0
  3. data/.gitignore +3 -1
  4. data/.rubocop.yml +4 -1
  5. data/ChangeLog +60 -0
  6. data/Gemfile +3 -0
  7. data/README.md +264 -0
  8. data/Rakefile +1 -9
  9. data/doclib/msgpack/factory.rb +47 -3
  10. data/doclib/msgpack/packer.rb +5 -4
  11. data/doclib/msgpack/time.rb +22 -0
  12. data/doclib/msgpack/timestamp.rb +44 -0
  13. data/doclib/msgpack/unpacker.rb +2 -2
  14. data/ext/java/org/msgpack/jruby/Buffer.java +23 -16
  15. data/ext/java/org/msgpack/jruby/Decoder.java +46 -23
  16. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  17. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +37 -49
  18. data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
  19. data/ext/java/org/msgpack/jruby/Factory.java +47 -7
  20. data/ext/java/org/msgpack/jruby/Packer.java +29 -17
  21. data/ext/java/org/msgpack/jruby/Unpacker.java +72 -37
  22. data/ext/msgpack/buffer.c +4 -16
  23. data/ext/msgpack/buffer.h +46 -5
  24. data/ext/msgpack/buffer_class.c +23 -15
  25. data/ext/msgpack/compat.h +1 -12
  26. data/ext/msgpack/extconf.rb +39 -7
  27. data/ext/msgpack/factory_class.c +87 -20
  28. data/ext/msgpack/packer.c +58 -8
  29. data/ext/msgpack/packer.h +24 -16
  30. data/ext/msgpack/packer_class.c +29 -31
  31. data/ext/msgpack/packer_ext_registry.c +22 -30
  32. data/ext/msgpack/packer_ext_registry.h +38 -31
  33. data/ext/msgpack/unpacker.c +102 -70
  34. data/ext/msgpack/unpacker.h +10 -2
  35. data/ext/msgpack/unpacker_class.c +35 -52
  36. data/ext/msgpack/unpacker_ext_registry.c +40 -16
  37. data/ext/msgpack/unpacker_ext_registry.h +21 -14
  38. data/lib/msgpack/bigint.rb +69 -0
  39. data/lib/msgpack/factory.rb +103 -0
  40. data/lib/msgpack/symbol.rb +21 -4
  41. data/lib/msgpack/time.rb +29 -0
  42. data/lib/msgpack/timestamp.rb +76 -0
  43. data/lib/msgpack/version.rb +4 -7
  44. data/lib/msgpack.rb +8 -12
  45. data/msgpack.gemspec +3 -7
  46. data/spec/bigint_spec.rb +26 -0
  47. data/spec/factory_spec.rb +299 -12
  48. data/spec/msgpack_spec.rb +1 -1
  49. data/spec/packer_spec.rb +18 -0
  50. data/spec/spec_helper.rb +30 -3
  51. data/spec/timestamp_spec.rb +159 -0
  52. data/spec/unpacker_spec.rb +135 -4
  53. metadata +21 -51
  54. data/.travis.yml +0 -43
  55. data/README.rdoc +0 -209
@@ -29,6 +29,11 @@ static ID s_write;
29
29
  static ID s_append;
30
30
  static ID s_close;
31
31
 
32
+ static VALUE sym_read_reference_threshold;
33
+ static VALUE sym_write_reference_threshold;
34
+ static VALUE sym_io_buffer_size;
35
+
36
+
32
37
  #define BUFFER(from, name) \
33
38
  msgpack_buffer_t *name = NULL; \
34
39
  Data_Get_Struct(from, msgpack_buffer_t, name); \
@@ -62,24 +67,22 @@ static VALUE Buffer_alloc(VALUE klass)
62
67
 
63
68
  static ID get_partial_read_method(VALUE io)
64
69
  {
65
- if(rb_respond_to(io, s_readpartial)) {
70
+ if(io != Qnil && rb_respond_to(io, s_readpartial)) {
66
71
  return s_readpartial;
67
- } else if(rb_respond_to(io, s_read)) {
68
- return s_read;
69
- } else {
70
- return s_read;
71
72
  }
73
+ return s_read;
72
74
  }
73
75
 
74
76
  static ID get_write_all_method(VALUE io)
75
77
  {
76
- if(rb_respond_to(io, s_write)) {
77
- return s_write;
78
- } else if(rb_respond_to(io, s_append)) {
79
- return s_append;
80
- } else {
81
- return s_write;
78
+ if(io != Qnil) {
79
+ if(rb_respond_to(io, s_write)) {
80
+ return s_write;
81
+ } else if(rb_respond_to(io, s_append)) {
82
+ return s_append;
83
+ }
82
84
  }
85
+ return s_write;
83
86
  }
84
87
 
85
88
  void MessagePack_Buffer_set_options(msgpack_buffer_t* b, VALUE io, VALUE options)
@@ -91,17 +94,17 @@ void MessagePack_Buffer_set_options(msgpack_buffer_t* b, VALUE io, VALUE options
91
94
  if(options != Qnil) {
92
95
  VALUE v;
93
96
 
94
- v = rb_hash_aref(options, ID2SYM(rb_intern("read_reference_threshold")));
97
+ v = rb_hash_aref(options, sym_read_reference_threshold);
95
98
  if(v != Qnil) {
96
99
  msgpack_buffer_set_read_reference_threshold(b, NUM2ULONG(v));
97
100
  }
98
101
 
99
- v = rb_hash_aref(options, ID2SYM(rb_intern("write_reference_threshold")));
102
+ v = rb_hash_aref(options, sym_write_reference_threshold);
100
103
  if(v != Qnil) {
101
104
  msgpack_buffer_set_write_reference_threshold(b, NUM2ULONG(v));
102
105
  }
103
106
 
104
- v = rb_hash_aref(options, ID2SYM(rb_intern("io_buffer_size")));
107
+ v = rb_hash_aref(options, sym_io_buffer_size);
105
108
  if(v != Qnil) {
106
109
  msgpack_buffer_set_io_buffer_size(b, NUM2ULONG(v));
107
110
  }
@@ -245,10 +248,11 @@ static VALUE read_until_eof_rescue(VALUE args)
245
248
  return Qnil;
246
249
  }
247
250
 
248
- static VALUE read_until_eof_error(VALUE args)
251
+ static VALUE read_until_eof_error(VALUE args, VALUE error)
249
252
  {
250
253
  /* ignore EOFError */
251
254
  UNUSED(args);
255
+ UNUSED(error);
252
256
  return Qnil;
253
257
  }
254
258
 
@@ -480,6 +484,10 @@ void MessagePack_Buffer_module_init(VALUE mMessagePack)
480
484
  s_append = rb_intern("<<");
481
485
  s_close = rb_intern("close");
482
486
 
487
+ sym_read_reference_threshold = ID2SYM(rb_intern("read_reference_threshold"));
488
+ sym_write_reference_threshold = ID2SYM(rb_intern("write_reference_threshold"));
489
+ sym_io_buffer_size = ID2SYM(rb_intern("io_buffer_size"));
490
+
483
491
  msgpack_buffer_static_init();
484
492
 
485
493
  cMessagePack_Buffer = rb_define_class_under(mMessagePack, "Buffer", rb_cObject);
data/ext/msgpack/compat.h CHANGED
@@ -20,6 +20,7 @@
20
20
 
21
21
  #include <stdbool.h>
22
22
  #include "ruby.h"
23
+ #include "ruby/encoding.h"
23
24
 
24
25
  #if defined(HAVE_RUBY_ST_H)
25
26
  # include "ruby/st.h" /* ruby hash on Ruby 1.9 */
@@ -38,18 +39,6 @@
38
39
  # define ZALLOC_N(type,n) RB_ZALLOC_N(type,n)
39
40
  #endif
40
41
 
41
- /*
42
- * COMPAT_HAVE_ENCODING
43
- */
44
- #ifdef HAVE_RUBY_ENCODING_H
45
- # include "ruby/encoding.h"
46
- # define COMPAT_HAVE_ENCODING
47
- #endif
48
-
49
- #if defined(__MACRUBY__) /* MacRuby */
50
- # undef COMPAT_HAVE_ENCODING
51
- #endif
52
-
53
42
 
54
43
  /*
55
44
  * define STR_DUP_LIKELY_DOES_COPY
@@ -2,13 +2,7 @@ require 'mkmf'
2
2
 
3
3
  have_header("ruby/st.h")
4
4
  have_header("st.h")
5
- have_func("rb_str_replace", ["ruby.h"])
6
- have_func("rb_intern_str", ["ruby.h"])
7
- have_func("rb_sym2str", ["ruby.h"])
8
- have_func("rb_str_intern", ["ruby.h"])
9
- have_func("rb_block_lambda", ["ruby.h"])
10
- have_func("rb_hash_dup", ["ruby.h"])
11
- have_func("rb_hash_clear", ["ruby.h"])
5
+ have_func("rb_enc_interned_str", "ruby.h")
12
6
 
13
7
  unless RUBY_PLATFORM.include? 'mswin'
14
8
  $CFLAGS << %[ -I.. -Wall -O3 -g -std=gnu99]
@@ -25,6 +19,44 @@ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
25
19
  $CFLAGS << %[ -DDISABLE_RMEM]
26
20
  end
27
21
 
22
+ # checking if Hash#[]= (rb_hash_aset) dedupes string keys
23
+ h = {}
24
+ x = {}
25
+ r = rand.to_s
26
+ h[%W(#{r}).join('')] = :foo
27
+ x[%W(#{r}).join('')] = :foo
28
+ if x.keys[0].equal?(h.keys[0])
29
+ $CFLAGS << ' -DHASH_ASET_DEDUPE=1 '
30
+ else
31
+ $CFLAGS << ' -DHASH_ASET_DEDUPE=0 '
32
+ end
33
+
34
+
35
+ # checking if String#-@ (str_uminus) dedupes... '
36
+ begin
37
+ a = -(%w(t e s t).join)
38
+ b = -(%w(t e s t).join)
39
+ if a.equal?(b)
40
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
41
+ else
42
+ $CFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
43
+ end
44
+ rescue NoMethodError
45
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
46
+ end
47
+
48
+ # checking if String#-@ (str_uminus) directly interns frozen strings... '
49
+ begin
50
+ s = rand.to_s.freeze
51
+ if (-s).equal?(s) && (-s.dup).equal?(s)
52
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
53
+ else
54
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
55
+ end
56
+ rescue NoMethodError
57
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
58
+ end
59
+
28
60
  if warnflags = CONFIG['warnflags']
29
61
  warnflags.slice!(/ -Wdeclaration-after-statement/)
30
62
  end
@@ -30,8 +30,11 @@ typedef struct msgpack_factory_t msgpack_factory_t;
30
30
 
31
31
  struct msgpack_factory_t {
32
32
  msgpack_packer_ext_registry_t pkrg;
33
- msgpack_unpacker_ext_registry_t ukrg;
33
+ msgpack_unpacker_ext_registry_t *ukrg;
34
+ bool has_bigint_ext_type;
34
35
  bool has_symbol_ext_type;
36
+ bool optimized_symbol_ext_type;
37
+ int symbol_ext_type;
35
38
  };
36
39
 
37
40
  #define FACTORY(from, name) \
@@ -47,14 +50,14 @@ static void Factory_free(msgpack_factory_t* fc)
47
50
  return;
48
51
  }
49
52
  msgpack_packer_ext_registry_destroy(&fc->pkrg);
50
- msgpack_unpacker_ext_registry_destroy(&fc->ukrg);
53
+ msgpack_unpacker_ext_registry_release(fc->ukrg);
51
54
  xfree(fc);
52
55
  }
53
56
 
54
57
  void Factory_mark(msgpack_factory_t* fc)
55
58
  {
56
59
  msgpack_packer_ext_registry_mark(&fc->pkrg);
57
- msgpack_unpacker_ext_registry_mark(&fc->ukrg);
60
+ msgpack_unpacker_ext_registry_mark(fc->ukrg);
58
61
  }
59
62
 
60
63
  static VALUE Factory_alloc(VALUE klass)
@@ -70,7 +73,7 @@ static VALUE Factory_initialize(int argc, VALUE* argv, VALUE self)
70
73
  FACTORY(self, fc);
71
74
 
72
75
  msgpack_packer_ext_registry_init(&fc->pkrg);
73
- msgpack_unpacker_ext_registry_init(&fc->ukrg);
76
+ // fc->ukrg is lazily initialized
74
77
 
75
78
  fc->has_symbol_ext_type = false;
76
79
 
@@ -85,6 +88,41 @@ static VALUE Factory_initialize(int argc, VALUE* argv, VALUE self)
85
88
  return Qnil;
86
89
  }
87
90
 
91
+ static VALUE Factory_dup(VALUE self)
92
+ {
93
+ VALUE clone = Factory_alloc(rb_obj_class(self));
94
+
95
+ FACTORY(self, fc);
96
+ FACTORY(clone, cloned_fc);
97
+
98
+ cloned_fc->has_symbol_ext_type = fc->has_symbol_ext_type;
99
+ cloned_fc->pkrg = fc->pkrg;
100
+ msgpack_unpacker_ext_registry_borrow(fc->ukrg, &cloned_fc->ukrg);
101
+ msgpack_packer_ext_registry_dup(&fc->pkrg, &cloned_fc->pkrg);
102
+
103
+ return clone;
104
+ }
105
+
106
+ static VALUE Factory_freeze(VALUE self) {
107
+ if(!rb_obj_frozen_p(self)) {
108
+ FACTORY(self, fc);
109
+
110
+ if (RTEST(fc->pkrg.hash)) {
111
+ rb_hash_freeze(fc->pkrg.hash);
112
+ if (!RTEST(fc->pkrg.cache)) {
113
+ // If the factory is frozen, we can safely share the packer cache between
114
+ // all packers. So we eagerly create it now so it's available when #packer
115
+ // is called.
116
+ fc->pkrg.cache = rb_hash_new();
117
+ }
118
+ }
119
+
120
+ rb_obj_freeze(self);
121
+ }
122
+
123
+ return self;
124
+ }
125
+
88
126
  VALUE MessagePack_Factory_packer(int argc, VALUE* argv, VALUE self)
89
127
  {
90
128
  FACTORY(self, fc);
@@ -97,6 +135,7 @@ VALUE MessagePack_Factory_packer(int argc, VALUE* argv, VALUE self)
97
135
 
98
136
  msgpack_packer_ext_registry_destroy(&pk->ext_registry);
99
137
  msgpack_packer_ext_registry_dup(&fc->pkrg, &pk->ext_registry);
138
+ pk->has_bigint_ext_type = fc->has_bigint_ext_type;
100
139
  pk->has_symbol_ext_type = fc->has_symbol_ext_type;
101
140
 
102
141
  return packer;
@@ -111,9 +150,9 @@ VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self)
111
150
 
112
151
  msgpack_unpacker_t* uk;
113
152
  Data_Get_Struct(unpacker, msgpack_unpacker_t, uk);
114
-
115
- msgpack_unpacker_ext_registry_destroy(&uk->ext_registry);
116
- msgpack_unpacker_ext_registry_dup(&fc->ukrg, &uk->ext_registry);
153
+ msgpack_unpacker_ext_registry_borrow(fc->ukrg, &uk->ext_registry);
154
+ uk->optimized_symbol_ext_type = fc->optimized_symbol_ext_type;
155
+ uk->symbol_ext_type = fc->symbol_ext_type;
117
156
 
118
157
  return unpacker;
119
158
  }
@@ -123,16 +162,19 @@ static VALUE Factory_registered_types_internal(VALUE self)
123
162
  FACTORY(self, fc);
124
163
 
125
164
  VALUE uk_mapping = rb_hash_new();
126
- for(int i=0; i < 256; i++) {
127
- if(fc->ukrg.array[i] != Qnil) {
128
- rb_hash_aset(uk_mapping, INT2FIX(i - 128), fc->ukrg.array[i]);
165
+ if (fc->ukrg) {
166
+ for(int i=0; i < 256; i++) {
167
+ if(fc->ukrg->array[i] != Qnil) {
168
+ rb_hash_aset(uk_mapping, INT2FIX(i - 128), fc->ukrg->array[i]);
169
+ }
129
170
  }
130
171
  }
131
- #ifdef HAVE_RB_HASH_DUP
132
- return rb_ary_new3(2, rb_hash_dup(fc->pkrg.hash), uk_mapping);
133
- #else
134
- return rb_ary_new3(2, rb_funcall(fc->pkrg.hash, rb_intern("dup"), 0), uk_mapping);
135
- #endif
172
+
173
+ return rb_ary_new3(
174
+ 2,
175
+ RTEST(fc->pkrg.hash) ? rb_hash_dup(fc->pkrg.hash) : rb_hash_new(),
176
+ uk_mapping
177
+ );
136
178
  }
137
179
 
138
180
  static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
@@ -140,8 +182,9 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
140
182
  FACTORY(self, fc);
141
183
 
142
184
  int ext_type;
185
+ int flags = 0;
143
186
  VALUE ext_module;
144
- VALUE options;
187
+ VALUE options = Qnil;
145
188
  VALUE packer_arg, unpacker_arg;
146
189
  VALUE packer_proc, unpacker_proc;
147
190
 
@@ -168,6 +211,10 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
168
211
  rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..3)", argc);
169
212
  }
170
213
 
214
+ if (options != Qnil) {
215
+ Check_Type(options, T_HASH);
216
+ }
217
+
171
218
  ext_type = NUM2INT(argv[0]);
172
219
  if(ext_type < -128 || ext_type > 127) {
173
220
  rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
@@ -188,18 +235,36 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
188
235
  if(unpacker_arg != Qnil) {
189
236
  if(rb_type(unpacker_arg) == T_SYMBOL || rb_type(unpacker_arg) == T_STRING) {
190
237
  unpacker_proc = rb_obj_method(ext_module, unpacker_arg);
238
+ } else if (rb_respond_to(unpacker_arg, rb_intern("call"))) {
239
+ unpacker_proc = unpacker_arg;
191
240
  } else {
192
241
  unpacker_proc = rb_funcall(unpacker_arg, rb_intern("method"), 1, ID2SYM(rb_intern("call")));
193
242
  }
194
243
  }
195
244
 
196
- msgpack_packer_ext_registry_put(&fc->pkrg, ext_module, ext_type, packer_proc, packer_arg);
197
-
198
- if (ext_module == rb_cSymbol) {
245
+ if(ext_module == rb_cSymbol) {
199
246
  fc->has_symbol_ext_type = true;
247
+ if(RTEST(options) && RTEST(rb_hash_aref(options, ID2SYM(rb_intern("optimized_symbols_parsing"))))) {
248
+ fc->optimized_symbol_ext_type = true;
249
+ }
250
+ }
251
+
252
+ if(RTEST(options)) {
253
+ if(RTEST(rb_hash_aref(options, ID2SYM(rb_intern("oversized_integer_extension"))))) {
254
+ if(ext_module == rb_cInteger) {
255
+ fc->has_bigint_ext_type = true;
256
+ } else {
257
+ rb_raise(rb_eArgError, "oversized_integer_extension: true is only for Integer class");
258
+ }
259
+ }
260
+
261
+ if(RTEST(rb_hash_aref(options, ID2SYM(rb_intern("recursive"))))) {
262
+ flags |= MSGPACK_EXT_RECURSIVE;
263
+ }
200
264
  }
201
265
 
202
- msgpack_unpacker_ext_registry_put(&fc->ukrg, ext_module, ext_type, unpacker_proc, unpacker_arg);
266
+ msgpack_packer_ext_registry_put(&fc->pkrg, ext_module, ext_type, flags, packer_proc, packer_arg);
267
+ msgpack_unpacker_ext_registry_put(&fc->ukrg, ext_module, ext_type, flags, unpacker_proc, unpacker_arg);
203
268
 
204
269
  return Qnil;
205
270
  }
@@ -211,6 +276,8 @@ void MessagePack_Factory_module_init(VALUE mMessagePack)
211
276
  rb_define_alloc_func(cMessagePack_Factory, Factory_alloc);
212
277
 
213
278
  rb_define_method(cMessagePack_Factory, "initialize", Factory_initialize, -1);
279
+ rb_define_method(cMessagePack_Factory, "dup", Factory_dup, 0);
280
+ rb_define_method(cMessagePack_Factory, "freeze", Factory_freeze, 0);
214
281
 
215
282
  rb_define_method(cMessagePack_Factory, "packer", MessagePack_Factory_packer, -1);
216
283
  rb_define_method(cMessagePack_Factory, "unpacker", MessagePack_Factory_unpacker, -1);
data/ext/msgpack/packer.c CHANGED
@@ -121,17 +121,61 @@ void msgpack_packer_write_hash_value(msgpack_packer_t* pk, VALUE v)
121
121
  #endif
122
122
  }
123
123
 
124
- void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
124
+ struct msgpack_call_proc_args_t;
125
+ typedef struct msgpack_call_proc_args_t msgpack_call_proc_args_t;
126
+ struct msgpack_call_proc_args_t {
127
+ VALUE proc;
128
+ VALUE arg;
129
+ VALUE packer;
130
+ };
131
+
132
+ VALUE msgpack_packer_try_calling_proc(VALUE value)
133
+ {
134
+ msgpack_call_proc_args_t *args = (msgpack_call_proc_args_t *)value;
135
+ return rb_funcall(args->proc, s_call, 2, args->arg, args->packer);
136
+ }
137
+
138
+ bool msgpack_packer_try_write_with_ext_type_lookup(msgpack_packer_t* pk, VALUE v)
125
139
  {
126
- int ext_type;
140
+ int ext_type, ext_flags;
127
141
 
128
- VALUE proc = msgpack_packer_ext_registry_lookup(&pk->ext_registry, v, &ext_type);
142
+ VALUE proc = msgpack_packer_ext_registry_lookup(&pk->ext_registry, v, &ext_type, &ext_flags);
129
143
 
130
- if(proc != Qnil) {
144
+ if(proc == Qnil) {
145
+ return false;
146
+ }
147
+
148
+ if(ext_flags & MSGPACK_EXT_RECURSIVE) {
149
+ msgpack_buffer_t parent_buffer = pk->buffer;
150
+ msgpack_buffer_init(PACKER_BUFFER_(pk));
151
+
152
+ int exception_occured = 0;
153
+ msgpack_call_proc_args_t args = { proc, v, pk->to_msgpack_arg };
154
+ rb_protect(msgpack_packer_try_calling_proc, (VALUE)&args, &exception_occured);
155
+
156
+ if (exception_occured) {
157
+ msgpack_buffer_destroy(PACKER_BUFFER_(pk));
158
+ pk->buffer = parent_buffer;
159
+ rb_jump_tag(exception_occured); // re-raise the exception
160
+ } else {
161
+ VALUE payload = msgpack_buffer_all_as_string(PACKER_BUFFER_(pk));
162
+ StringValue(payload);
163
+ msgpack_buffer_destroy(PACKER_BUFFER_(pk));
164
+ pk->buffer = parent_buffer;
165
+ msgpack_packer_write_ext(pk, ext_type, payload);
166
+ }
167
+ } else {
131
168
  VALUE payload = rb_funcall(proc, s_call, 1, v);
132
169
  StringValue(payload);
133
170
  msgpack_packer_write_ext(pk, ext_type, payload);
134
- } else {
171
+ }
172
+
173
+ return true;
174
+ }
175
+
176
+ void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
177
+ {
178
+ if(!(msgpack_packer_try_write_with_ext_type_lookup(pk, v))) {
135
179
  rb_funcall(v, pk->to_msgpack_method, 1, pk->to_msgpack_arg);
136
180
  }
137
181
  }
@@ -155,13 +199,19 @@ void msgpack_packer_write_value(msgpack_packer_t* pk, VALUE v)
155
199
  msgpack_packer_write_symbol_value(pk, v);
156
200
  break;
157
201
  case T_STRING:
158
- msgpack_packer_write_string_value(pk, v);
202
+ if(rb_class_of(v) == rb_cString || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
203
+ msgpack_packer_write_string_value(pk, v);
204
+ }
159
205
  break;
160
206
  case T_ARRAY:
161
- msgpack_packer_write_array_value(pk, v);
207
+ if(rb_class_of(v) == rb_cArray || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
208
+ msgpack_packer_write_array_value(pk, v);
209
+ }
162
210
  break;
163
211
  case T_HASH:
164
- msgpack_packer_write_hash_value(pk, v);
212
+ if(rb_class_of(v) == rb_cHash || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
213
+ msgpack_packer_write_hash_value(pk, v);
214
+ }
165
215
  break;
166
216
  case T_BIGNUM:
167
217
  msgpack_packer_write_bignum_value(pk, v);
data/ext/msgpack/packer.h CHANGED
@@ -32,6 +32,7 @@ struct msgpack_packer_t {
32
32
  msgpack_buffer_t buffer;
33
33
 
34
34
  bool compatibility_mode;
35
+ bool has_bigint_ext_type;
35
36
  bool has_symbol_ext_type;
36
37
 
37
38
  ID to_msgpack_method;
@@ -56,6 +57,8 @@ void msgpack_packer_destroy(msgpack_packer_t* pk);
56
57
 
57
58
  void msgpack_packer_mark(msgpack_packer_t* pk);
58
59
 
60
+ bool msgpack_packer_try_write_with_ext_type_lookup(msgpack_packer_t* pk, VALUE v);
61
+
59
62
  static inline void msgpack_packer_set_to_msgpack_method(msgpack_packer_t* pk,
60
63
  ID to_msgpack_method, VALUE to_msgpack_arg)
61
64
  {
@@ -396,7 +399,6 @@ static inline void msgpack_packer_write_ext(msgpack_packer_t* pk, int ext_type,
396
399
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), payload);
397
400
  }
398
401
 
399
- #ifdef COMPAT_HAVE_ENCODING
400
402
  static inline bool msgpack_packer_is_binary(VALUE v, int encindex)
401
403
  {
402
404
  return encindex == msgpack_rb_encindex_ascii8bit;
@@ -414,7 +416,6 @@ static inline bool msgpack_packer_is_utf8_compat_string(VALUE v, int encindex)
414
416
  #endif
415
417
  ;
416
418
  }
417
- #endif
418
419
 
419
420
  static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE v)
420
421
  {
@@ -425,7 +426,6 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
425
426
  rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %lu", len, 0xffffffffUL);
426
427
  }
427
428
 
428
- #ifdef COMPAT_HAVE_ENCODING
429
429
  int encindex = ENCODING_GET(v);
430
430
  if(msgpack_packer_is_binary(v, encindex) && !pk->compatibility_mode) {
431
431
  /* write ASCII-8BIT string using Binary type */
@@ -443,24 +443,11 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
443
443
  msgpack_packer_write_raw_header(pk, (unsigned int)len);
444
444
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
445
445
  }
446
- #else
447
- msgpack_packer_write_raw_header(pk, (unsigned int)len);
448
- msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
449
- #endif
450
446
  }
451
447
 
452
448
  static inline void msgpack_packer_write_symbol_string_value(msgpack_packer_t* pk, VALUE v)
453
449
  {
454
- #ifdef HAVE_RB_SYM2STR
455
- /* rb_sym2str is added since MRI 2.2.0 */
456
450
  msgpack_packer_write_string_value(pk, rb_sym2str(v));
457
- #else
458
- VALUE str = rb_id2str(SYM2ID(v));
459
- if (!str) {
460
- rb_raise(rb_eRuntimeError, "could not convert a symbol to string");
461
- }
462
- msgpack_packer_write_string_value(pk, str);
463
- #endif
464
451
  }
465
452
 
466
453
  void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v);
@@ -485,9 +472,30 @@ static inline void msgpack_packer_write_fixnum_value(msgpack_packer_t* pk, VALUE
485
472
 
486
473
  static inline void msgpack_packer_write_bignum_value(msgpack_packer_t* pk, VALUE v)
487
474
  {
475
+ int leading_zero_bits;
476
+ size_t required_size = rb_absint_size(v, &leading_zero_bits);
477
+
488
478
  if(RBIGNUM_POSITIVE_P(v)) {
479
+ if(required_size > 8 && pk->has_bigint_ext_type) {
480
+ if(msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
481
+ return;
482
+ }
483
+ // if we didn't return here `msgpack_packer_write_u64` will raise a RangeError
484
+ }
485
+
489
486
  msgpack_packer_write_u64(pk, rb_big2ull(v));
490
487
  } else {
488
+ if(leading_zero_bits == 0) {
489
+ required_size += 1;
490
+ }
491
+
492
+ if(required_size > 8 && pk->has_bigint_ext_type) {
493
+ if(msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
494
+ return;
495
+ }
496
+ // if we didn't return here `msgpack_packer_write_u64` will raise a RangeError
497
+ }
498
+
491
499
  msgpack_packer_write_long_long(pk, rb_big2ll(v));
492
500
  }
493
501
  }
@@ -28,6 +28,8 @@ VALUE cMessagePack_Packer;
28
28
  static ID s_to_msgpack;
29
29
  static ID s_write;
30
30
 
31
+ static VALUE sym_compatibility_mode;
32
+
31
33
  //static VALUE s_packer_value;
32
34
  //static msgpack_packer_t* s_packer;
33
35
 
@@ -68,29 +70,28 @@ VALUE MessagePack_Packer_alloc(VALUE klass)
68
70
 
69
71
  VALUE MessagePack_Packer_initialize(int argc, VALUE* argv, VALUE self)
70
72
  {
73
+ if(argc > 2) {
74
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc);
75
+ }
76
+
71
77
  VALUE io = Qnil;
72
78
  VALUE options = Qnil;
73
79
 
74
- if(argc == 0 || (argc == 1 && argv[0] == Qnil)) {
75
- /* Qnil */
76
-
77
- } else if(argc == 1) {
78
- VALUE v = argv[0];
79
- if(rb_type(v) == T_HASH) {
80
- options = v;
81
- } else {
82
- io = v;
83
- }
84
-
85
- } else if(argc == 2) {
80
+ if(argc >= 1) {
86
81
  io = argv[0];
82
+ }
83
+
84
+ if(argc == 2) {
87
85
  options = argv[1];
88
- if(rb_type(options) != T_HASH) {
89
- rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
90
- }
86
+ }
91
87
 
92
- } else {
93
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc);
88
+ if (options == Qnil && rb_type(io) == T_HASH) {
89
+ options = io;
90
+ io = Qnil;
91
+ }
92
+
93
+ if(options != Qnil) {
94
+ Check_Type(options, T_HASH);
94
95
  }
95
96
 
96
97
  PACKER(self, pk);
@@ -103,7 +104,7 @@ VALUE MessagePack_Packer_initialize(int argc, VALUE* argv, VALUE self)
103
104
  if(options != Qnil) {
104
105
  VALUE v;
105
106
 
106
- v = rb_hash_aref(options, ID2SYM(rb_intern("compatibility_mode")));
107
+ v = rb_hash_aref(options, sym_compatibility_mode);
107
108
  msgpack_packer_set_compat(pk, RTEST(v));
108
109
  }
109
110
 
@@ -281,7 +282,7 @@ static VALUE Packer_flush(VALUE self)
281
282
  return self;
282
283
  }
283
284
 
284
- static VALUE Packer_clear(VALUE self)
285
+ static VALUE Packer_reset(VALUE self)
285
286
  {
286
287
  PACKER(self, pk);
287
288
  msgpack_buffer_clear(PACKER_BUFFER_(pk));
@@ -339,11 +340,10 @@ static VALUE Packer_write_to(VALUE self, VALUE io)
339
340
  static VALUE Packer_registered_types_internal(VALUE self)
340
341
  {
341
342
  PACKER(self, pk);
342
- #ifdef HAVE_RB_HASH_DUP
343
- return rb_hash_dup(pk->ext_registry.hash);
344
- #else
345
- return rb_funcall(pk->ext_registry.hash, rb_intern("dup"), 0);
346
- #endif
343
+ if (RTEST(pk->ext_registry.hash)) {
344
+ return rb_hash_dup(pk->ext_registry.hash);
345
+ }
346
+ return rb_hash_new();
347
347
  }
348
348
 
349
349
  static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
@@ -359,12 +359,7 @@ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
359
359
  case 2:
360
360
  /* register_type(0x7f, Time) {|obj| block... } */
361
361
  rb_need_block();
362
- #ifdef HAVE_RB_BLOCK_LAMBDA
363
362
  proc = rb_block_lambda();
364
- #else
365
- /* MRI 1.8 */
366
- proc = rb_block_proc();
367
- #endif
368
363
  arg = proc;
369
364
  break;
370
365
  case 3:
@@ -386,7 +381,7 @@ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
386
381
  rb_raise(rb_eArgError, "expected Module/Class but found %s.", rb_obj_classname(ext_module));
387
382
  }
388
383
 
389
- msgpack_packer_ext_registry_put(&pk->ext_registry, ext_module, ext_type, proc, arg);
384
+ msgpack_packer_ext_registry_put(&pk->ext_registry, ext_module, ext_type, 0, proc, arg);
390
385
 
391
386
  if (ext_module == rb_cSymbol) {
392
387
  pk->has_symbol_ext_type = true;
@@ -418,6 +413,8 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
418
413
  s_to_msgpack = rb_intern("to_msgpack");
419
414
  s_write = rb_intern("write");
420
415
 
416
+ sym_compatibility_mode = ID2SYM(rb_intern("compatibility_mode"));
417
+
421
418
  msgpack_packer_static_init();
422
419
  msgpack_packer_ext_registry_static_init();
423
420
 
@@ -449,7 +446,8 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
449
446
  rb_define_method(cMessagePack_Packer, "flush", Packer_flush, 0);
450
447
 
451
448
  /* delegation methods */
452
- rb_define_method(cMessagePack_Packer, "clear", Packer_clear, 0);
449
+ rb_define_method(cMessagePack_Packer, "reset", Packer_reset, 0);
450
+ rb_define_alias(cMessagePack_Packer, "clear", "reset");
453
451
  rb_define_method(cMessagePack_Packer, "size", Packer_size, 0);
454
452
  rb_define_method(cMessagePack_Packer, "empty?", Packer_empty_p, 0);
455
453
  rb_define_method(cMessagePack_Packer, "write_to", Packer_write_to, 1);