msgpack 1.4.2 → 1.7.3

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 (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
  }