msgpack 1.4.2 → 1.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +89 -0
  3. data/README.md +73 -13
  4. data/ext/java/org/msgpack/jruby/Buffer.java +26 -19
  5. data/ext/java/org/msgpack/jruby/Decoder.java +29 -21
  6. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  7. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +43 -64
  8. data/ext/java/org/msgpack/jruby/ExtensionValue.java +6 -9
  9. data/ext/java/org/msgpack/jruby/Factory.java +43 -42
  10. data/ext/java/org/msgpack/jruby/Packer.java +37 -40
  11. data/ext/java/org/msgpack/jruby/Unpacker.java +80 -73
  12. data/ext/msgpack/buffer.c +54 -74
  13. data/ext/msgpack/buffer.h +21 -18
  14. data/ext/msgpack/buffer_class.c +161 -52
  15. data/ext/msgpack/buffer_class.h +1 -0
  16. data/ext/msgpack/compat.h +0 -99
  17. data/ext/msgpack/extconf.rb +25 -46
  18. data/ext/msgpack/factory_class.c +143 -87
  19. data/ext/msgpack/packer.c +66 -43
  20. data/ext/msgpack/packer.h +25 -20
  21. data/ext/msgpack/packer_class.c +102 -130
  22. data/ext/msgpack/packer_class.h +11 -0
  23. data/ext/msgpack/packer_ext_registry.c +35 -40
  24. data/ext/msgpack/packer_ext_registry.h +41 -38
  25. data/ext/msgpack/rbinit.c +1 -1
  26. data/ext/msgpack/rmem.c +3 -4
  27. data/ext/msgpack/sysdep.h +5 -2
  28. data/ext/msgpack/unpacker.c +136 -111
  29. data/ext/msgpack/unpacker.h +16 -13
  30. data/ext/msgpack/unpacker_class.c +86 -126
  31. data/ext/msgpack/unpacker_class.h +11 -0
  32. data/ext/msgpack/unpacker_ext_registry.c +40 -28
  33. data/ext/msgpack/unpacker_ext_registry.h +21 -18
  34. data/lib/msgpack/bigint.rb +69 -0
  35. data/lib/msgpack/buffer.rb +9 -0
  36. data/lib/msgpack/factory.rb +140 -10
  37. data/lib/msgpack/packer.rb +10 -1
  38. data/lib/msgpack/symbol.rb +21 -4
  39. data/lib/msgpack/time.rb +1 -1
  40. data/lib/msgpack/unpacker.rb +14 -1
  41. data/lib/msgpack/version.rb +1 -1
  42. data/lib/msgpack.rb +6 -7
  43. data/msgpack.gemspec +8 -5
  44. metadata +37 -82
  45. data/.gitignore +0 -23
  46. data/.rubocop.yml +0 -36
  47. data/.travis.yml +0 -39
  48. data/Gemfile +0 -9
  49. data/Rakefile +0 -71
  50. data/appveyor.yml +0 -18
  51. data/bench/pack.rb +0 -23
  52. data/bench/pack_log.rb +0 -33
  53. data/bench/pack_log_long.rb +0 -65
  54. data/bench/pack_symbols.rb +0 -28
  55. data/bench/run.sh +0 -14
  56. data/bench/run_long.sh +0 -35
  57. data/bench/run_symbols.sh +0 -26
  58. data/bench/unpack.rb +0 -21
  59. data/bench/unpack_log.rb +0 -34
  60. data/bench/unpack_log_long.rb +0 -67
  61. data/doclib/msgpack/buffer.rb +0 -193
  62. data/doclib/msgpack/core_ext.rb +0 -101
  63. data/doclib/msgpack/error.rb +0 -19
  64. data/doclib/msgpack/extension_value.rb +0 -9
  65. data/doclib/msgpack/factory.rb +0 -101
  66. data/doclib/msgpack/packer.rb +0 -208
  67. data/doclib/msgpack/time.rb +0 -22
  68. data/doclib/msgpack/timestamp.rb +0 -44
  69. data/doclib/msgpack/unpacker.rb +0 -183
  70. data/doclib/msgpack.rb +0 -87
  71. data/msgpack.org.md +0 -46
  72. data/spec/cases.json +0 -1
  73. data/spec/cases.msg +0 -0
  74. data/spec/cases_compact.msg +0 -0
  75. data/spec/cases_spec.rb +0 -39
  76. data/spec/cruby/buffer_io_spec.rb +0 -255
  77. data/spec/cruby/buffer_packer.rb +0 -29
  78. data/spec/cruby/buffer_spec.rb +0 -575
  79. data/spec/cruby/buffer_unpacker.rb +0 -19
  80. data/spec/cruby/unpacker_spec.rb +0 -70
  81. data/spec/ext_value_spec.rb +0 -99
  82. data/spec/exttypes.rb +0 -51
  83. data/spec/factory_spec.rb +0 -367
  84. data/spec/format_spec.rb +0 -301
  85. data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
  86. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
  87. data/spec/jruby/unpacker_spec.rb +0 -186
  88. data/spec/msgpack_spec.rb +0 -214
  89. data/spec/pack_spec.rb +0 -61
  90. data/spec/packer_spec.rb +0 -557
  91. data/spec/random_compat.rb +0 -24
  92. data/spec/spec_helper.rb +0 -55
  93. data/spec/timestamp_spec.rb +0 -121
  94. data/spec/unpack_spec.rb +0 -57
  95. data/spec/unpacker_spec.rb +0 -819
@@ -30,47 +30,76 @@ 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
- #define FACTORY(from, name) \
38
- msgpack_factory_t *name = NULL; \
39
- Data_Get_Struct(from, msgpack_factory_t, name); \
40
- if(name == NULL) { \
41
- rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \
42
- }
43
-
44
- static void Factory_free(msgpack_factory_t* fc)
40
+ static void Factory_free(void *ptr)
45
41
  {
42
+ msgpack_factory_t *fc = ptr;
43
+
46
44
  if(fc == NULL) {
47
45
  return;
48
46
  }
49
47
  msgpack_packer_ext_registry_destroy(&fc->pkrg);
50
- msgpack_unpacker_ext_registry_destroy(&fc->ukrg);
48
+ msgpack_unpacker_ext_registry_release(fc->ukrg);
51
49
  xfree(fc);
52
50
  }
53
51
 
54
- void Factory_mark(msgpack_factory_t* fc)
52
+ void Factory_mark(void *ptr)
55
53
  {
54
+ msgpack_factory_t *fc = ptr;
56
55
  msgpack_packer_ext_registry_mark(&fc->pkrg);
57
- msgpack_unpacker_ext_registry_mark(&fc->ukrg);
56
+ msgpack_unpacker_ext_registry_mark(fc->ukrg);
58
57
  }
59
58
 
60
- static VALUE Factory_alloc(VALUE klass)
59
+ static size_t Factory_memsize(const void *ptr)
61
60
  {
62
- msgpack_factory_t* fc = ZALLOC_N(msgpack_factory_t, 1);
61
+ const msgpack_factory_t *fc = ptr;
62
+ size_t total_size = sizeof(msgpack_factory_t);
63
63
 
64
- VALUE self = Data_Wrap_Struct(klass, Factory_mark, Factory_free, fc);
65
- return self;
64
+ if (fc->ukrg) {
65
+ total_size += sizeof(msgpack_unpacker_ext_registry_t) / (fc->ukrg->borrow_count + 1);
66
+ }
67
+
68
+ return total_size;
69
+ }
70
+
71
+ static const rb_data_type_t factory_data_type = {
72
+ .wrap_struct_name = "msgpack:factory",
73
+ .function = {
74
+ .dmark = Factory_mark,
75
+ .dfree = Factory_free,
76
+ .dsize = Factory_memsize,
77
+ },
78
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
79
+ };
80
+
81
+ static inline msgpack_factory_t *Factory_get(VALUE object)
82
+ {
83
+ msgpack_factory_t *factory;
84
+ TypedData_Get_Struct(object, msgpack_factory_t, &factory_data_type, factory);
85
+ if (!factory) {
86
+ rb_raise(rb_eArgError, "Uninitialized Factory object");
87
+ }
88
+ return factory;
89
+ }
90
+
91
+ static VALUE Factory_alloc(VALUE klass)
92
+ {
93
+ msgpack_factory_t *fc;
94
+ return TypedData_Make_Struct(klass, msgpack_factory_t, &factory_data_type, fc);
66
95
  }
67
96
 
68
97
  static VALUE Factory_initialize(int argc, VALUE* argv, VALUE self)
69
98
  {
70
- FACTORY(self, fc);
99
+ msgpack_factory_t *fc = Factory_get(self);
71
100
 
72
- msgpack_packer_ext_registry_init(&fc->pkrg);
73
- msgpack_unpacker_ext_registry_init(&fc->ukrg);
101
+ msgpack_packer_ext_registry_init(self, &fc->pkrg);
102
+ // fc->ukrg is lazily initialized
74
103
 
75
104
  fc->has_symbol_ext_type = false;
76
105
 
@@ -85,18 +114,52 @@ static VALUE Factory_initialize(int argc, VALUE* argv, VALUE self)
85
114
  return Qnil;
86
115
  }
87
116
 
117
+ static VALUE Factory_dup(VALUE self)
118
+ {
119
+ VALUE clone = Factory_alloc(rb_obj_class(self));
120
+
121
+ msgpack_factory_t *fc = Factory_get(self);
122
+ msgpack_factory_t *cloned_fc = Factory_get(clone);
123
+
124
+ cloned_fc->has_symbol_ext_type = fc->has_symbol_ext_type;
125
+ cloned_fc->pkrg = fc->pkrg;
126
+ msgpack_unpacker_ext_registry_borrow(fc->ukrg, &cloned_fc->ukrg);
127
+ msgpack_packer_ext_registry_dup(clone, &fc->pkrg, &cloned_fc->pkrg);
128
+
129
+ return clone;
130
+ }
131
+
132
+ static VALUE Factory_freeze(VALUE self) {
133
+ if(!rb_obj_frozen_p(self)) {
134
+ msgpack_factory_t *fc = Factory_get(self);
135
+
136
+ if (RTEST(fc->pkrg.hash)) {
137
+ rb_hash_freeze(fc->pkrg.hash);
138
+ if (!RTEST(fc->pkrg.cache)) {
139
+ // If the factory is frozen, we can safely share the packer cache between
140
+ // all packers. So we eagerly create it now so it's available when #packer
141
+ // is called.
142
+ RB_OBJ_WRITE(self, &fc->pkrg.cache, rb_hash_new());
143
+ }
144
+ }
145
+
146
+ rb_obj_freeze(self);
147
+ }
148
+
149
+ return self;
150
+ }
151
+
88
152
  VALUE MessagePack_Factory_packer(int argc, VALUE* argv, VALUE self)
89
153
  {
90
- FACTORY(self, fc);
154
+ msgpack_factory_t *fc = Factory_get(self);
91
155
 
92
156
  VALUE packer = MessagePack_Packer_alloc(cMessagePack_Packer);
93
157
  MessagePack_Packer_initialize(argc, argv, packer);
94
158
 
95
- msgpack_packer_t* pk;
96
- Data_Get_Struct(packer, msgpack_packer_t, pk);
97
-
159
+ msgpack_packer_t* pk = MessagePack_Packer_get(packer);
98
160
  msgpack_packer_ext_registry_destroy(&pk->ext_registry);
99
- msgpack_packer_ext_registry_dup(&fc->pkrg, &pk->ext_registry);
161
+ msgpack_packer_ext_registry_borrow(packer, &fc->pkrg, &pk->ext_registry);
162
+ pk->has_bigint_ext_type = fc->has_bigint_ext_type;
100
163
  pk->has_symbol_ext_type = fc->has_symbol_ext_type;
101
164
 
102
165
  return packer;
@@ -104,102 +167,93 @@ VALUE MessagePack_Factory_packer(int argc, VALUE* argv, VALUE self)
104
167
 
105
168
  VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self)
106
169
  {
107
- FACTORY(self, fc);
170
+ msgpack_factory_t *fc = Factory_get(self);
108
171
 
109
172
  VALUE unpacker = MessagePack_Unpacker_alloc(cMessagePack_Unpacker);
110
173
  MessagePack_Unpacker_initialize(argc, argv, unpacker);
111
174
 
112
- msgpack_unpacker_t* uk;
113
- 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);
175
+ msgpack_unpacker_t* uk = MessagePack_Unpacker_get(unpacker);
176
+ msgpack_unpacker_ext_registry_borrow(fc->ukrg, &uk->ext_registry);
177
+ uk->optimized_symbol_ext_type = fc->optimized_symbol_ext_type;
178
+ uk->symbol_ext_type = fc->symbol_ext_type;
117
179
 
118
180
  return unpacker;
119
181
  }
120
182
 
121
183
  static VALUE Factory_registered_types_internal(VALUE self)
122
184
  {
123
- FACTORY(self, fc);
185
+ msgpack_factory_t *fc = Factory_get(self);
124
186
 
125
187
  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]);
188
+ if (fc->ukrg) {
189
+ for(int i=0; i < 256; i++) {
190
+ if(!NIL_P(fc->ukrg->array[i])) {
191
+ rb_hash_aset(uk_mapping, INT2FIX(i - 128), fc->ukrg->array[i]);
192
+ }
129
193
  }
130
194
  }
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
195
+
196
+ return rb_ary_new3(
197
+ 2,
198
+ RTEST(fc->pkrg.hash) ? rb_hash_dup(fc->pkrg.hash) : rb_hash_new(),
199
+ uk_mapping
200
+ );
136
201
  }
137
202
 
138
- static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
203
+ static VALUE Factory_register_type_internal(VALUE self, VALUE rb_ext_type, VALUE ext_module, VALUE options)
139
204
  {
140
- FACTORY(self, fc);
205
+ msgpack_factory_t *fc = Factory_get(self);
141
206
 
142
- int ext_type;
143
- VALUE ext_module;
144
- VALUE options;
145
- VALUE packer_arg, unpacker_arg;
146
- VALUE packer_proc, unpacker_proc;
207
+ Check_Type(rb_ext_type, T_FIXNUM);
147
208
 
148
- if (OBJ_FROZEN(self)) {
149
- rb_raise(rb_eRuntimeError, "can't modify frozen Factory");
209
+ if(rb_type(ext_module) != T_MODULE && rb_type(ext_module) != T_CLASS) {
210
+ rb_raise(rb_eArgError, "expected Module/Class but found %s.", rb_obj_classname(ext_module));
150
211
  }
151
212
 
152
- switch (argc) {
153
- case 2:
154
- /* register_type(0x7f, Time) */
155
- packer_arg = ID2SYM(rb_intern("to_msgpack_ext"));
156
- unpacker_arg = ID2SYM(rb_intern("from_msgpack_ext"));
157
- break;
158
- case 3:
159
- /* register_type(0x7f, Time, packer: proc-like, unapcker: proc-like) */
160
- options = argv[2];
161
- if(rb_type(options) != T_HASH) {
162
- rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
163
- }
164
- packer_arg = rb_hash_aref(options, ID2SYM(rb_intern("packer")));
165
- unpacker_arg = rb_hash_aref(options, ID2SYM(rb_intern("unpacker")));
166
- break;
167
- default:
168
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..3)", argc);
169
- }
213
+ int flags = 0;
170
214
 
171
- ext_type = NUM2INT(argv[0]);
172
- if(ext_type < -128 || ext_type > 127) {
173
- rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
215
+ VALUE packer_proc = Qnil;
216
+ VALUE unpacker_proc = Qnil;
217
+ if(!NIL_P(options)) {
218
+ Check_Type(options, T_HASH);
219
+ packer_proc = rb_hash_aref(options, ID2SYM(rb_intern("packer")));
220
+ unpacker_proc = rb_hash_aref(options, ID2SYM(rb_intern("unpacker")));
174
221
  }
175
222
 
176
- ext_module = argv[1];
177
- if(rb_type(ext_module) != T_MODULE && rb_type(ext_module) != T_CLASS) {
178
- rb_raise(rb_eArgError, "expected Module/Class but found %s.", rb_obj_classname(ext_module));
223
+ if (OBJ_FROZEN(self)) {
224
+ rb_raise(rb_eFrozenError, "can't modify frozen MessagePack::Factory");
179
225
  }
180
226
 
181
- packer_proc = Qnil;
182
- unpacker_proc = Qnil;
183
-
184
- if(packer_arg != Qnil) {
185
- packer_proc = rb_funcall(packer_arg, rb_intern("to_proc"), 0);
227
+ int ext_type = NUM2INT(rb_ext_type);
228
+ if(ext_type < -128 || ext_type > 127) {
229
+ rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
186
230
  }
187
231
 
188
- if(unpacker_arg != Qnil) {
189
- if(rb_type(unpacker_arg) == T_SYMBOL || rb_type(unpacker_arg) == T_STRING) {
190
- unpacker_proc = rb_obj_method(ext_module, unpacker_arg);
191
- } else {
192
- unpacker_proc = rb_funcall(unpacker_arg, rb_intern("method"), 1, ID2SYM(rb_intern("call")));
232
+ if(ext_module == rb_cSymbol) {
233
+ if(NIL_P(options) || RTEST(rb_hash_aref(options, ID2SYM(rb_intern("packer"))))) {
234
+ fc->has_symbol_ext_type = true;
235
+ }
236
+ if(RTEST(options) && RTEST(rb_hash_aref(options, ID2SYM(rb_intern("optimized_symbols_parsing"))))) {
237
+ fc->optimized_symbol_ext_type = true;
193
238
  }
194
239
  }
195
240
 
196
- msgpack_packer_ext_registry_put(&fc->pkrg, ext_module, ext_type, packer_proc, packer_arg);
241
+ if(RTEST(options)) {
242
+ if(RTEST(rb_hash_aref(options, ID2SYM(rb_intern("oversized_integer_extension"))))) {
243
+ if(ext_module == rb_cInteger) {
244
+ fc->has_bigint_ext_type = true;
245
+ } else {
246
+ rb_raise(rb_eArgError, "oversized_integer_extension: true is only for Integer class");
247
+ }
248
+ }
197
249
 
198
- if (ext_module == rb_cSymbol) {
199
- fc->has_symbol_ext_type = true;
250
+ if(RTEST(rb_hash_aref(options, ID2SYM(rb_intern("recursive"))))) {
251
+ flags |= MSGPACK_EXT_RECURSIVE;
252
+ }
200
253
  }
201
254
 
202
- msgpack_unpacker_ext_registry_put(&fc->ukrg, ext_module, ext_type, unpacker_proc, unpacker_arg);
255
+ msgpack_packer_ext_registry_put(self, &fc->pkrg, ext_module, ext_type, flags, packer_proc);
256
+ msgpack_unpacker_ext_registry_put(self, &fc->ukrg, ext_module, ext_type, flags, unpacker_proc);
203
257
 
204
258
  return Qnil;
205
259
  }
@@ -211,10 +265,12 @@ void MessagePack_Factory_module_init(VALUE mMessagePack)
211
265
  rb_define_alloc_func(cMessagePack_Factory, Factory_alloc);
212
266
 
213
267
  rb_define_method(cMessagePack_Factory, "initialize", Factory_initialize, -1);
268
+ rb_define_method(cMessagePack_Factory, "dup", Factory_dup, 0);
269
+ rb_define_method(cMessagePack_Factory, "freeze", Factory_freeze, 0);
214
270
 
215
271
  rb_define_method(cMessagePack_Factory, "packer", MessagePack_Factory_packer, -1);
216
272
  rb_define_method(cMessagePack_Factory, "unpacker", MessagePack_Factory_unpacker, -1);
217
273
 
218
274
  rb_define_private_method(cMessagePack_Factory, "registered_types_internal", Factory_registered_types_internal, 0);
219
- rb_define_method(cMessagePack_Factory, "register_type", Factory_register_type, -1);
275
+ rb_define_private_method(cMessagePack_Factory, "register_type_internal", Factory_register_type_internal, 3);
220
276
  }
data/ext/msgpack/packer.c CHANGED
@@ -17,35 +17,14 @@
17
17
  */
18
18
 
19
19
  #include "packer.h"
20
+ #include "buffer_class.h"
20
21
 
21
- #ifdef RUBINIUS
22
- static ID s_to_iter;
23
- static ID s_next;
24
- static ID s_key;
25
- static ID s_value;
22
+ #if !defined(HAVE_RB_PROC_CALL_WITH_BLOCK)
23
+ #define rb_proc_call_with_block(recv, argc, argv, block) rb_funcallv(recv, rb_intern("call"), argc, argv)
26
24
  #endif
27
25
 
28
- static ID s_call;
29
-
30
- void msgpack_packer_static_init()
31
- {
32
- #ifdef RUBINIUS
33
- s_to_iter = rb_intern("to_iter");
34
- s_next = rb_intern("next");
35
- s_key = rb_intern("key");
36
- s_value = rb_intern("value");
37
- #endif
38
-
39
- s_call = rb_intern("call");
40
- }
41
-
42
- void msgpack_packer_static_destroy()
43
- { }
44
-
45
26
  void msgpack_packer_init(msgpack_packer_t* pk)
46
27
  {
47
- memset(pk, 0, sizeof(msgpack_packer_t));
48
-
49
28
  msgpack_buffer_init(PACKER_BUFFER_(pk));
50
29
  }
51
30
 
@@ -59,6 +38,7 @@ void msgpack_packer_mark(msgpack_packer_t* pk)
59
38
  /* See MessagePack_Buffer_wrap */
60
39
  /* msgpack_buffer_mark(PACKER_BUFFER_(pk)); */
61
40
  rb_gc_mark(pk->buffer_ref);
41
+ rb_gc_mark(pk->to_msgpack_arg);
62
42
  }
63
43
 
64
44
  void msgpack_packer_reset(msgpack_packer_t* pk)
@@ -108,30 +88,67 @@ void msgpack_packer_write_hash_value(msgpack_packer_t* pk, VALUE v)
108
88
  unsigned int len32 = (unsigned int)len;
109
89
  msgpack_packer_write_map_header(pk, len32);
110
90
 
111
- #ifdef RUBINIUS
112
- VALUE iter = rb_funcall(v, s_to_iter, 0);
113
- VALUE entry = Qnil;
114
- while(RTEST(entry = rb_funcall(iter, s_next, 1, entry))) {
115
- VALUE key = rb_funcall(entry, s_key, 0);
116
- VALUE val = rb_funcall(entry, s_value, 0);
117
- write_hash_foreach(key, val, (VALUE) pk);
118
- }
119
- #else
120
91
  rb_hash_foreach(v, write_hash_foreach, (VALUE) pk);
121
- #endif
122
92
  }
123
93
 
124
- void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
94
+ struct msgpack_call_proc_args_t;
95
+ typedef struct msgpack_call_proc_args_t msgpack_call_proc_args_t;
96
+ struct msgpack_call_proc_args_t {
97
+ VALUE proc;
98
+ VALUE args[2];
99
+ };
100
+
101
+ VALUE msgpack_packer_try_calling_proc(VALUE value)
125
102
  {
126
- int ext_type;
103
+ msgpack_call_proc_args_t *args = (msgpack_call_proc_args_t *)value;
104
+ return rb_proc_call_with_block(args->proc, 2, args->args, Qnil);
105
+ }
127
106
 
128
- VALUE proc = msgpack_packer_ext_registry_lookup(&pk->ext_registry, v, &ext_type);
107
+ bool msgpack_packer_try_write_with_ext_type_lookup(msgpack_packer_t* pk, VALUE v)
108
+ {
109
+ int ext_type, ext_flags;
110
+
111
+ VALUE proc = msgpack_packer_ext_registry_lookup(&pk->ext_registry, v, &ext_type, &ext_flags);
112
+
113
+ if(proc == Qnil) {
114
+ return false;
115
+ }
129
116
 
130
- if(proc != Qnil) {
131
- VALUE payload = rb_funcall(proc, s_call, 1, v);
117
+ if(ext_flags & MSGPACK_EXT_RECURSIVE) {
118
+ VALUE held_buffer = MessagePack_Buffer_hold(&pk->buffer);
119
+
120
+ msgpack_buffer_t parent_buffer = pk->buffer;
121
+ msgpack_buffer_init(PACKER_BUFFER_(pk));
122
+
123
+ int exception_occured = 0;
124
+ msgpack_call_proc_args_t args = { proc, { v, pk->to_msgpack_arg } };
125
+ rb_protect(msgpack_packer_try_calling_proc, (VALUE)&args, &exception_occured);
126
+
127
+ if (exception_occured) {
128
+ msgpack_buffer_destroy(PACKER_BUFFER_(pk));
129
+ pk->buffer = parent_buffer;
130
+ rb_jump_tag(exception_occured); // re-raise the exception
131
+ } else {
132
+ VALUE payload = msgpack_buffer_all_as_string(PACKER_BUFFER_(pk));
133
+ StringValue(payload);
134
+ msgpack_buffer_destroy(PACKER_BUFFER_(pk));
135
+ pk->buffer = parent_buffer;
136
+ msgpack_packer_write_ext(pk, ext_type, payload);
137
+ }
138
+
139
+ RB_GC_GUARD(held_buffer);
140
+ } else {
141
+ VALUE payload = rb_proc_call_with_block(proc, 1, &v, Qnil);
132
142
  StringValue(payload);
133
143
  msgpack_packer_write_ext(pk, ext_type, payload);
134
- } else {
144
+ }
145
+
146
+ return true;
147
+ }
148
+
149
+ void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
150
+ {
151
+ if(!(msgpack_packer_try_write_with_ext_type_lookup(pk, v))) {
135
152
  rb_funcall(v, pk->to_msgpack_method, 1, pk->to_msgpack_arg);
136
153
  }
137
154
  }
@@ -155,13 +172,19 @@ void msgpack_packer_write_value(msgpack_packer_t* pk, VALUE v)
155
172
  msgpack_packer_write_symbol_value(pk, v);
156
173
  break;
157
174
  case T_STRING:
158
- msgpack_packer_write_string_value(pk, v);
175
+ if(rb_class_of(v) == rb_cString || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
176
+ msgpack_packer_write_string_value(pk, v);
177
+ }
159
178
  break;
160
179
  case T_ARRAY:
161
- msgpack_packer_write_array_value(pk, v);
180
+ if(rb_class_of(v) == rb_cArray || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
181
+ msgpack_packer_write_array_value(pk, v);
182
+ }
162
183
  break;
163
184
  case T_HASH:
164
- msgpack_packer_write_hash_value(pk, v);
185
+ if(rb_class_of(v) == rb_cHash || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
186
+ msgpack_packer_write_hash_value(pk, v);
187
+ }
165
188
  break;
166
189
  case T_BIGNUM:
167
190
  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;
@@ -46,16 +47,14 @@ struct msgpack_packer_t {
46
47
 
47
48
  #define PACKER_BUFFER_(pk) (&(pk)->buffer)
48
49
 
49
- void msgpack_packer_static_init();
50
-
51
- void msgpack_packer_static_destroy();
52
-
53
50
  void msgpack_packer_init(msgpack_packer_t* pk);
54
51
 
55
52
  void msgpack_packer_destroy(msgpack_packer_t* pk);
56
53
 
57
54
  void msgpack_packer_mark(msgpack_packer_t* pk);
58
55
 
56
+ bool msgpack_packer_try_write_with_ext_type_lookup(msgpack_packer_t* pk, VALUE v);
57
+
59
58
  static inline void msgpack_packer_set_to_msgpack_method(msgpack_packer_t* pk,
60
59
  ID to_msgpack_method, VALUE to_msgpack_arg)
61
60
  {
@@ -405,13 +404,7 @@ static inline bool msgpack_packer_is_utf8_compat_string(VALUE v, int encindex)
405
404
  {
406
405
  return encindex == msgpack_rb_encindex_utf8
407
406
  || encindex == msgpack_rb_encindex_usascii
408
- #ifdef ENC_CODERANGE_ASCIIONLY
409
- /* Because ENC_CODERANGE_ASCIIONLY does not scan string, it may return ENC_CODERANGE_UNKNOWN unlike */
410
- /* rb_enc_str_asciionly_p. It is always faster than rb_str_encode if it is available. */
411
- /* Very old Rubinius (< v1.3.1) doesn't have ENC_CODERANGE_ASCIIONLY. */
412
- || (rb_enc_asciicompat(rb_enc_from_index(encindex)) && ENC_CODERANGE_ASCIIONLY(v))
413
- #endif
414
- ;
407
+ || (rb_enc_asciicompat(rb_enc_from_index(encindex)) && ENC_CODERANGE_ASCIIONLY(v));
415
408
  }
416
409
 
417
410
  static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE v)
@@ -444,16 +437,7 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
444
437
 
445
438
  static inline void msgpack_packer_write_symbol_string_value(msgpack_packer_t* pk, VALUE v)
446
439
  {
447
- #ifdef HAVE_RB_SYM2STR
448
- /* rb_sym2str is added since MRI 2.2.0 */
449
440
  msgpack_packer_write_string_value(pk, rb_sym2str(v));
450
- #else
451
- VALUE str = rb_id2str(SYM2ID(v));
452
- if (!str) {
453
- rb_raise(rb_eRuntimeError, "could not convert a symbol to string");
454
- }
455
- msgpack_packer_write_string_value(pk, str);
456
- #endif
457
441
  }
458
442
 
459
443
  void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v);
@@ -478,9 +462,30 @@ static inline void msgpack_packer_write_fixnum_value(msgpack_packer_t* pk, VALUE
478
462
 
479
463
  static inline void msgpack_packer_write_bignum_value(msgpack_packer_t* pk, VALUE v)
480
464
  {
465
+ int leading_zero_bits;
466
+ size_t required_size = rb_absint_size(v, &leading_zero_bits);
467
+
481
468
  if(RBIGNUM_POSITIVE_P(v)) {
469
+ if(required_size > 8 && pk->has_bigint_ext_type) {
470
+ if(msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
471
+ return;
472
+ }
473
+ // if we didn't return here `msgpack_packer_write_u64` will raise a RangeError
474
+ }
475
+
482
476
  msgpack_packer_write_u64(pk, rb_big2ull(v));
483
477
  } else {
478
+ if(leading_zero_bits == 0) {
479
+ required_size += 1;
480
+ }
481
+
482
+ if(required_size > 8 && pk->has_bigint_ext_type) {
483
+ if(msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
484
+ return;
485
+ }
486
+ // if we didn't return here `msgpack_packer_write_u64` will raise a RangeError
487
+ }
488
+
484
489
  msgpack_packer_write_long_long(pk, rb_big2ll(v));
485
490
  }
486
491
  }