msgpack 1.4.3 → 1.5.0

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +7 -6
  3. data/ChangeLog +18 -0
  4. data/README.md +22 -0
  5. data/Rakefile +1 -2
  6. data/doclib/msgpack/factory.rb +46 -3
  7. data/doclib/msgpack/packer.rb +5 -4
  8. data/doclib/msgpack/unpacker.rb +2 -2
  9. data/ext/java/org/msgpack/jruby/Buffer.java +6 -0
  10. data/ext/java/org/msgpack/jruby/Decoder.java +23 -19
  11. data/ext/java/org/msgpack/jruby/Encoder.java +45 -18
  12. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +28 -40
  13. data/ext/java/org/msgpack/jruby/Factory.java +40 -5
  14. data/ext/java/org/msgpack/jruby/Packer.java +21 -11
  15. data/ext/java/org/msgpack/jruby/Unpacker.java +44 -22
  16. data/ext/msgpack/buffer.h +2 -2
  17. data/ext/msgpack/buffer_class.c +23 -15
  18. data/ext/msgpack/factory_class.c +78 -16
  19. data/ext/msgpack/packer.c +42 -5
  20. data/ext/msgpack/packer.h +24 -0
  21. data/ext/msgpack/packer_class.c +29 -22
  22. data/ext/msgpack/packer_ext_registry.c +23 -9
  23. data/ext/msgpack/packer_ext_registry.h +38 -31
  24. data/ext/msgpack/unpacker.c +37 -19
  25. data/ext/msgpack/unpacker.h +2 -2
  26. data/ext/msgpack/unpacker_class.c +26 -45
  27. data/ext/msgpack/unpacker_ext_registry.c +40 -16
  28. data/ext/msgpack/unpacker_ext_registry.h +21 -14
  29. data/lib/msgpack/bigint.rb +69 -0
  30. data/lib/msgpack/factory.rb +103 -0
  31. data/lib/msgpack/symbol.rb +8 -1
  32. data/lib/msgpack/version.rb +1 -1
  33. data/lib/msgpack.rb +4 -5
  34. data/msgpack.gemspec +1 -2
  35. data/spec/bigint_spec.rb +26 -0
  36. data/spec/factory_spec.rb +263 -14
  37. data/spec/spec_helper.rb +3 -4
  38. data/spec/timestamp_spec.rb +0 -2
  39. data/spec/unpacker_spec.rb +22 -3
  40. metadata +7 -29
@@ -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,7 +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
- return rb_hash_dup(pk->ext_registry.hash);
343
+ if (RTEST(pk->ext_registry.hash)) {
344
+ return rb_hash_dup(pk->ext_registry.hash);
345
+ }
346
+ return rb_hash_new();
343
347
  }
344
348
 
345
349
  static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
@@ -377,7 +381,7 @@ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
377
381
  rb_raise(rb_eArgError, "expected Module/Class but found %s.", rb_obj_classname(ext_module));
378
382
  }
379
383
 
380
- 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);
381
385
 
382
386
  if (ext_module == rb_cSymbol) {
383
387
  pk->has_symbol_ext_type = true;
@@ -409,6 +413,8 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
409
413
  s_to_msgpack = rb_intern("to_msgpack");
410
414
  s_write = rb_intern("write");
411
415
 
416
+ sym_compatibility_mode = ID2SYM(rb_intern("compatibility_mode"));
417
+
412
418
  msgpack_packer_static_init();
413
419
  msgpack_packer_ext_registry_static_init();
414
420
 
@@ -440,7 +446,8 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
440
446
  rb_define_method(cMessagePack_Packer, "flush", Packer_flush, 0);
441
447
 
442
448
  /* delegation methods */
443
- 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");
444
451
  rb_define_method(cMessagePack_Packer, "size", Packer_size, 0);
445
452
  rb_define_method(cMessagePack_Packer, "empty?", Packer_empty_p, 0);
446
453
  rb_define_method(cMessagePack_Packer, "write_to", Packer_write_to, 1);
@@ -30,8 +30,8 @@ void msgpack_packer_ext_registry_static_destroy()
30
30
 
31
31
  void msgpack_packer_ext_registry_init(msgpack_packer_ext_registry_t* pkrg)
32
32
  {
33
- pkrg->hash = rb_hash_new();
34
- pkrg->cache = rb_hash_new();
33
+ pkrg->hash = Qnil;
34
+ pkrg->cache = Qnil;
35
35
  }
36
36
 
37
37
  void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg)
@@ -43,15 +43,29 @@ void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg)
43
43
  void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src,
44
44
  msgpack_packer_ext_registry_t* dst)
45
45
  {
46
- dst->hash = rb_hash_dup(src->hash);
47
- dst->cache = rb_hash_dup(src->cache);
46
+ if(RTEST(src->hash) && !rb_obj_frozen_p(src->hash)) {
47
+ dst->hash = rb_hash_dup(src->hash);
48
+ dst->cache = RTEST(src->cache) ? rb_hash_dup(src->cache) : Qnil;
49
+ } else {
50
+ // If the type registry is frozen we can safely share it, and share the cache as well.
51
+ dst->hash = src->hash;
52
+ dst->cache = src->cache;
53
+ }
48
54
  }
49
55
 
50
56
  VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg,
51
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg)
57
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg)
52
58
  {
53
- VALUE e = rb_ary_new3(3, INT2FIX(ext_type), proc, arg);
54
- /* clear lookup cache not to miss added type */
55
- rb_hash_clear(pkrg->cache);
56
- return rb_hash_aset(pkrg->hash, ext_module, e);
59
+ if (!RTEST(pkrg->hash)) {
60
+ pkrg->hash = rb_hash_new();
61
+ }
62
+
63
+ if (RTEST(pkrg->cache)) {
64
+ /* clear lookup cache not to miss added type */
65
+ rb_hash_clear(pkrg->cache);
66
+ }
67
+
68
+ // TODO: Ruby embeded array limit is 3, merging `proc` and `arg` would be good.
69
+ VALUE entry = rb_ary_new3(4, INT2FIX(ext_type), proc, arg, INT2FIX(flags));
70
+ return rb_hash_aset(pkrg->hash, ext_module, entry);
57
71
  }
@@ -21,6 +21,8 @@
21
21
  #include "compat.h"
22
22
  #include "ruby.h"
23
23
 
24
+ #define MSGPACK_EXT_RECURSIVE 0b0001
25
+
24
26
  struct msgpack_packer_ext_registry_t;
25
27
  typedef struct msgpack_packer_ext_registry_t msgpack_packer_ext_registry_t;
26
28
 
@@ -44,7 +46,7 @@ void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src,
44
46
  msgpack_packer_ext_registry_t* dst);
45
47
 
46
48
  VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg,
47
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg);
49
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg);
48
50
 
49
51
  static int msgpack_packer_ext_find_superclass(VALUE key, VALUE value, VALUE arg)
50
52
  {
@@ -60,59 +62,60 @@ static int msgpack_packer_ext_find_superclass(VALUE key, VALUE value, VALUE arg)
60
62
  }
61
63
 
62
64
  static inline VALUE msgpack_packer_ext_registry_fetch(msgpack_packer_ext_registry_t* pkrg,
63
- VALUE lookup_class, int* ext_type_result)
65
+ VALUE lookup_class, int* ext_type_result, int* ext_flags_result)
64
66
  {
65
67
  // fetch lookup_class from hash, which is a hash to register classes
66
68
  VALUE type = rb_hash_lookup(pkrg->hash, lookup_class);
67
69
  if(type != Qnil) {
68
70
  *ext_type_result = FIX2INT(rb_ary_entry(type, 0));
71
+ *ext_flags_result = FIX2INT(rb_ary_entry(type, 3));
69
72
  return rb_ary_entry(type, 1);
70
73
  }
71
74
 
72
75
  // fetch lookup_class from cache, which stores results of searching ancestors from pkrg->hash
73
- VALUE type_inht = rb_hash_lookup(pkrg->cache, lookup_class);
74
- if(type_inht != Qnil) {
75
- *ext_type_result = FIX2INT(rb_ary_entry(type_inht, 0));
76
- return rb_ary_entry(type_inht, 1);
76
+ if (RTEST(pkrg->cache)) {
77
+ VALUE type_inht = rb_hash_lookup(pkrg->cache, lookup_class);
78
+ if(type_inht != Qnil) {
79
+ *ext_type_result = FIX2INT(rb_ary_entry(type_inht, 0));
80
+ *ext_flags_result = FIX2INT(rb_ary_entry(type_inht, 3));
81
+ return rb_ary_entry(type_inht, 1);
82
+ }
77
83
  }
78
84
 
79
85
  return Qnil;
80
86
  }
81
87
 
82
88
  static inline VALUE msgpack_packer_ext_registry_lookup(msgpack_packer_ext_registry_t* pkrg,
83
- VALUE instance, int* ext_type_result)
89
+ VALUE instance, int* ext_type_result, int* ext_flags_result)
84
90
  {
85
- VALUE lookup_class;
86
91
  VALUE type;
87
92
 
88
- /*
89
- * 1. check whether singleton_class of this instance is registered (or resolved in past) or not.
90
- *
91
- * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
92
- * String have no singleton class and raise a TypeError when trying to get
93
- * it. See implementation of #singleton_class in ruby's source code:
94
- * VALUE rb_singleton_class(VALUE obj);
95
- *
96
- * Since all but symbols are already filtered out when reaching this code
97
- * only symbols are checked here.
98
- */
99
- if (!SYMBOL_P(instance)) {
100
- lookup_class = rb_singleton_class(instance);
101
-
102
- type = msgpack_packer_ext_registry_fetch(pkrg, lookup_class, ext_type_result);
93
+ if (pkrg->hash == Qnil) { // No extensions registered
94
+ return Qnil;
95
+ }
103
96
 
104
- if(type != Qnil) {
105
- return type;
106
- }
97
+ /*
98
+ * 1. check whether singleton_class or class of this instance is registered (or resolved in past) or not.
99
+ *
100
+ * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
101
+ * `rb_class_of` returns the singleton_class if the object has one, or the "real class" otherwise.
102
+ */
103
+ VALUE lookup_class = rb_class_of(instance);
104
+ type = msgpack_packer_ext_registry_fetch(pkrg, lookup_class, ext_type_result, ext_flags_result);
105
+ if(type != Qnil) {
106
+ return type;
107
107
  }
108
108
 
109
109
  /*
110
- * 2. check the class of instance is registered (or resolved in past) or not.
110
+ * 2. If the object had a singleton_class check if the real class of instance is registered
111
+ * (or resolved in past) or not.
111
112
  */
112
- type = msgpack_packer_ext_registry_fetch(pkrg, rb_obj_class(instance), ext_type_result);
113
-
114
- if(type != Qnil) {
115
- return type;
113
+ VALUE real_class = rb_obj_class(instance);
114
+ if(lookup_class != real_class) {
115
+ type = msgpack_packer_ext_registry_fetch(pkrg, real_class, ext_type_result, ext_flags_result);
116
+ if(type != Qnil) {
117
+ return type;
118
+ }
116
119
  }
117
120
 
118
121
  /*
@@ -126,8 +129,12 @@ static inline VALUE msgpack_packer_ext_registry_lookup(msgpack_packer_ext_regist
126
129
  VALUE superclass = args[1];
127
130
  if(superclass != Qnil) {
128
131
  VALUE superclass_type = rb_hash_lookup(pkrg->hash, superclass);
132
+ if (!RTEST(pkrg->cache)) {
133
+ pkrg->cache = rb_hash_new();
134
+ }
129
135
  rb_hash_aset(pkrg->cache, lookup_class, superclass_type);
130
136
  *ext_type_result = FIX2INT(rb_ary_entry(superclass_type, 0));
137
+ *ext_flags_result = FIX2INT(rb_ary_entry(superclass_type, 3));
131
138
  return rb_ary_entry(superclass_type, 1);
132
139
  }
133
140
 
@@ -52,9 +52,9 @@ void msgpack_unpacker_static_destroy()
52
52
 
53
53
  #define HEAD_BYTE_REQUIRED 0xc1
54
54
 
55
- void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
55
+ msgpack_unpacker_t* _msgpack_unpacker_new(void)
56
56
  {
57
- memset(uk, 0, sizeof(msgpack_unpacker_t));
57
+ msgpack_unpacker_t* uk = ZALLOC_N(msgpack_unpacker_t, 1);
58
58
 
59
59
  msgpack_buffer_init(UNPACKER_BUFFER_(uk));
60
60
 
@@ -71,6 +71,8 @@ void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
71
71
  uk->stack = xmalloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_t));
72
72
  #endif
73
73
  uk->stack_capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
74
+
75
+ return uk;
74
76
  }
75
77
 
76
78
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
@@ -164,14 +166,17 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
164
166
  return object_complete_symbol(uk, rb_str_intern(str));
165
167
  }
166
168
 
167
- VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type);
169
+ int ext_flags;
170
+ VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type, &ext_flags);
171
+
168
172
  if(proc != Qnil) {
169
- VALUE obj = rb_funcall(proc, s_call, 1, str);
173
+ VALUE obj;
174
+ obj = rb_funcall(proc, s_call, 1, str == Qnil ? rb_str_buf_new(0) : str);
170
175
  return object_complete(uk, obj);
171
176
  }
172
177
 
173
178
  if(uk->allow_unknown_ext) {
174
- VALUE obj = MessagePack_ExtensionValue_new(ext_type, str);
179
+ VALUE obj = MessagePack_ExtensionValue_new(ext_type, str == Qnil ? rb_str_buf_new(0) : str);
175
180
  return object_complete(uk, obj);
176
181
  }
177
182
 
@@ -281,29 +286,42 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
281
286
  {
282
287
  /* assuming uk->reading_raw == Qnil */
283
288
 
289
+ int ext_flags;
290
+ VALUE proc;
291
+
292
+ if(!(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY)) {
293
+ proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, raw_type, &ext_flags);
294
+ if(proc != Qnil && ext_flags & MSGPACK_EXT_RECURSIVE) {
295
+ VALUE obj;
296
+ uk->last_object = Qnil;
297
+ reset_head_byte(uk);
298
+ size_t ext_size = uk->reading_raw_remaining;
299
+ uk->reading_raw_remaining = 0;
300
+ obj = rb_funcall(proc, s_call, 1, uk->buffer.owner);
301
+ msgpack_buffer_skip(UNPACKER_BUFFER_(uk), ext_size);
302
+ return object_complete(uk, obj);
303
+ }
304
+ }
305
+
284
306
  /* try optimized read */
285
307
  size_t length = uk->reading_raw_remaining;
286
308
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
287
309
  int ret;
288
310
  if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type) || (uk->symbolize_keys && is_reading_map_key(uk))) {
289
- VALUE symbol = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length);
311
+ VALUE symbol = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length, raw_type != RAW_TYPE_BINARY);
290
312
  ret = object_complete_symbol(uk, symbol);
291
313
  } else {
292
- /* don't use zerocopy for hash keys but get a frozen string directly
293
- * because rb_hash_aset freezes keys and it causes copying */
294
- bool will_freeze = uk->freeze || is_reading_map_key(uk);
295
- VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
314
+ bool will_freeze = uk->freeze;
296
315
  if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
316
+ /* don't use zerocopy for hash keys but get a frozen string directly
317
+ * because rb_hash_aset freezes keys and it causes copying */
318
+ will_freeze = will_freeze || is_reading_map_key(uk);
319
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
297
320
  ret = object_complete(uk, string);
298
321
  } else {
322
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, false, false);
299
323
  ret = object_complete_ext(uk, raw_type, string);
300
324
  }
301
-
302
- # if !HASH_ASET_DEDUPE
303
- if(will_freeze) {
304
- rb_obj_freeze(string);
305
- }
306
- # endif
307
325
  }
308
326
  uk->reading_raw_remaining = 0;
309
327
  return ret;
@@ -373,7 +391,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
373
391
  uint8_t length = cb->u8;
374
392
  int ext_type = (signed char) cb->buffer[1];
375
393
  if(length == 0) {
376
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
394
+ return object_complete_ext(uk, ext_type, Qnil);
377
395
  }
378
396
  uk->reading_raw_remaining = length;
379
397
  return read_raw_body_begin(uk, ext_type);
@@ -385,7 +403,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
385
403
  uint16_t length = _msgpack_be16(cb->u16);
386
404
  int ext_type = (signed char) cb->buffer[2];
387
405
  if(length == 0) {
388
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
406
+ return object_complete_ext(uk, ext_type, Qnil);
389
407
  }
390
408
  uk->reading_raw_remaining = length;
391
409
  return read_raw_body_begin(uk, ext_type);
@@ -397,7 +415,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
397
415
  uint32_t length = _msgpack_be32(cb->u32);
398
416
  int ext_type = (signed char) cb->buffer[4];
399
417
  if(length == 0) {
400
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
418
+ return object_complete_ext(uk, ext_type, Qnil);
401
419
  }
402
420
  uk->reading_raw_remaining = length;
403
421
  return read_raw_body_begin(uk, ext_type);
@@ -60,7 +60,7 @@ struct msgpack_unpacker_t {
60
60
 
61
61
  VALUE buffer_ref;
62
62
 
63
- msgpack_unpacker_ext_registry_t ext_registry;
63
+ msgpack_unpacker_ext_registry_t *ext_registry;
64
64
 
65
65
  /* options */
66
66
  bool symbolize_keys;
@@ -86,7 +86,7 @@ void msgpack_unpacker_static_init();
86
86
 
87
87
  void msgpack_unpacker_static_destroy();
88
88
 
89
- void _msgpack_unpacker_init(msgpack_unpacker_t* uk);
89
+ msgpack_unpacker_t* _msgpack_unpacker_new(void);
90
90
 
91
91
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk);
92
92
 
@@ -33,6 +33,10 @@ static VALUE eUnexpectedTypeError;
33
33
  static VALUE eUnknownExtTypeError;
34
34
  static VALUE mTypeError; // obsoleted. only for backward compatibility. See #86.
35
35
 
36
+ static VALUE sym_symbolize_keys;
37
+ static VALUE sym_freeze;
38
+ static VALUE sym_allow_unknown_ext;
39
+
36
40
  #define UNPACKER(from, name) \
37
41
  msgpack_unpacker_t *name = NULL; \
38
42
  Data_Get_Struct(from, msgpack_unpacker_t, name); \
@@ -45,7 +49,7 @@ static void Unpacker_free(msgpack_unpacker_t* uk)
45
49
  if(uk == NULL) {
46
50
  return;
47
51
  }
48
- msgpack_unpacker_ext_registry_destroy(&uk->ext_registry);
52
+ msgpack_unpacker_ext_registry_release(uk->ext_registry);
49
53
  _msgpack_unpacker_destroy(uk);
50
54
  xfree(uk);
51
55
  }
@@ -53,13 +57,12 @@ static void Unpacker_free(msgpack_unpacker_t* uk)
53
57
  static void Unpacker_mark(msgpack_unpacker_t* uk)
54
58
  {
55
59
  msgpack_unpacker_mark(uk);
56
- msgpack_unpacker_ext_registry_mark(&uk->ext_registry);
60
+ msgpack_unpacker_ext_registry_mark(uk->ext_registry);
57
61
  }
58
62
 
59
63
  VALUE MessagePack_Unpacker_alloc(VALUE klass)
60
64
  {
61
- msgpack_unpacker_t* uk = ZALLOC_N(msgpack_unpacker_t, 1);
62
- _msgpack_unpacker_init(uk);
65
+ msgpack_unpacker_t* uk = _msgpack_unpacker_new();
63
66
 
64
67
  VALUE self = Data_Wrap_Struct(klass, Unpacker_mark, Unpacker_free, uk);
65
68
  return self;
@@ -84,7 +87,7 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
84
87
  } else if(argc == 2) {
85
88
  io = argv[0];
86
89
  options = argv[1];
87
- if(rb_type(options) != T_HASH) {
90
+ if(options != Qnil && rb_type(options) != T_HASH) {
88
91
  rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
89
92
  }
90
93
 
@@ -94,7 +97,6 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
94
97
 
95
98
  UNPACKER(self, uk);
96
99
 
97
- msgpack_unpacker_ext_registry_init(&uk->ext_registry);
98
100
  uk->buffer_ref = MessagePack_Buffer_wrap(UNPACKER_BUFFER_(uk), self);
99
101
 
100
102
  MessagePack_Buffer_set_options(UNPACKER_BUFFER_(uk), io, options);
@@ -102,13 +104,13 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
102
104
  if(options != Qnil) {
103
105
  VALUE v;
104
106
 
105
- v = rb_hash_aref(options, ID2SYM(rb_intern("symbolize_keys")));
107
+ v = rb_hash_aref(options, sym_symbolize_keys);
106
108
  msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
107
109
 
108
- v = rb_hash_aref(options, ID2SYM(rb_intern("freeze")));
110
+ v = rb_hash_aref(options, sym_freeze);
109
111
  msgpack_unpacker_set_freeze(uk, RTEST(v));
110
112
 
111
- v = rb_hash_aref(options, ID2SYM(rb_intern("allow_unknown_ext")));
113
+ v = rb_hash_aref(options, sym_allow_unknown_ext);
112
114
  msgpack_unpacker_set_allow_unknown_ext(uk, RTEST(v));
113
115
  }
114
116
 
@@ -133,7 +135,7 @@ static VALUE Unpacker_allow_unknown_ext_p(VALUE self)
133
135
  return uk->allow_unknown_ext ? Qtrue : Qfalse;
134
136
  }
135
137
 
136
- static void raise_unpacker_error(int r)
138
+ NORETURN(static void raise_unpacker_error(int r))
137
139
  {
138
140
  switch(r) {
139
141
  case PRIMITIVE_EOF:
@@ -145,6 +147,7 @@ static void raise_unpacker_error(int r)
145
147
  case PRIMITIVE_UNEXPECTED_TYPE:
146
148
  rb_raise(eUnexpectedTypeError, "unexpected type");
147
149
  case PRIMITIVE_UNEXPECTED_EXT_TYPE:
150
+ // rb_bug("unexpected extension type");
148
151
  rb_raise(eUnknownExtTypeError, "unexpected extension type");
149
152
  default:
150
153
  rb_raise(eUnpackError, "logically unknown error %d", r);
@@ -222,34 +225,6 @@ static VALUE Unpacker_read_map_header(VALUE self)
222
225
  return ULONG2NUM(size);
223
226
  }
224
227
 
225
- static VALUE Unpacker_peek_next_type(VALUE self)
226
- {
227
- UNPACKER(self, uk);
228
-
229
- int r = msgpack_unpacker_peek_next_object_type(uk);
230
- if(r < 0) {
231
- raise_unpacker_error(r);
232
- }
233
-
234
- switch((enum msgpack_unpacker_object_type) r) {
235
- case TYPE_NIL:
236
- return rb_intern("nil");
237
- case TYPE_BOOLEAN:
238
- return rb_intern("boolean");
239
- case TYPE_INTEGER:
240
- return rb_intern("integer");
241
- case TYPE_FLOAT:
242
- return rb_intern("float");
243
- case TYPE_RAW:
244
- return rb_intern("raw");
245
- case TYPE_ARRAY:
246
- return rb_intern("array");
247
- case TYPE_MAP:
248
- return rb_intern("map");
249
- default:
250
- rb_raise(eUnpackError, "logically unknown type %d", r);
251
- }
252
- }
253
228
 
254
229
  static VALUE Unpacker_feed(VALUE self, VALUE data)
255
230
  {
@@ -296,9 +271,10 @@ static VALUE Unpacker_each_impl(VALUE self)
296
271
  }
297
272
  }
298
273
 
299
- static VALUE Unpacker_rescue_EOFError(VALUE self)
274
+ static VALUE Unpacker_rescue_EOFError(VALUE args, VALUE error)
300
275
  {
301
- UNUSED(self);
276
+ UNUSED(args);
277
+ UNUSED(error);
302
278
  return Qnil;
303
279
  }
304
280
 
@@ -347,9 +323,11 @@ static VALUE Unpacker_registered_types_internal(VALUE self)
347
323
  UNPACKER(self, uk);
348
324
 
349
325
  VALUE mapping = rb_hash_new();
350
- for(int i=0; i < 256; i++) {
351
- if(uk->ext_registry.array[i] != Qnil) {
352
- rb_hash_aset(mapping, INT2FIX(i - 128), uk->ext_registry.array[i]);
326
+ if (uk->ext_registry) {
327
+ for(int i=0; i < 256; i++) {
328
+ if(uk->ext_registry->array[i] != Qnil) {
329
+ rb_hash_aset(mapping, INT2FIX(i - 128), uk->ext_registry->array[i]);
330
+ }
353
331
  }
354
332
  }
355
333
 
@@ -388,7 +366,7 @@ static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
388
366
  rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
389
367
  }
390
368
 
391
- msgpack_unpacker_ext_registry_put(&uk->ext_registry, ext_module, ext_type, proc, arg);
369
+ msgpack_unpacker_ext_registry_put(&uk->ext_registry, ext_module, ext_type, 0, proc, arg);
392
370
 
393
371
  return Qnil;
394
372
  }
@@ -438,6 +416,10 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
438
416
 
439
417
  eUnknownExtTypeError = rb_define_class_under(mMessagePack, "UnknownExtTypeError", eUnpackError);
440
418
 
419
+ sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
420
+ sym_freeze = ID2SYM(rb_intern("freeze"));
421
+ sym_allow_unknown_ext = ID2SYM(rb_intern("allow_unknown_ext"));
422
+
441
423
  rb_define_alloc_func(cMessagePack_Unpacker, MessagePack_Unpacker_alloc);
442
424
 
443
425
  rb_define_method(cMessagePack_Unpacker, "initialize", MessagePack_Unpacker_initialize, -1);
@@ -451,7 +433,6 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
451
433
  rb_define_method(cMessagePack_Unpacker, "skip_nil", Unpacker_skip_nil, 0);
452
434
  rb_define_method(cMessagePack_Unpacker, "read_array_header", Unpacker_read_array_header, 0);
453
435
  rb_define_method(cMessagePack_Unpacker, "read_map_header", Unpacker_read_map_header, 0);
454
- //rb_define_method(cMessagePack_Unpacker, "peek_next_type", Unpacker_peek_next_type, 0); // TODO
455
436
  rb_define_method(cMessagePack_Unpacker, "feed", Unpacker_feed, 1);
456
437
  rb_define_method(cMessagePack_Unpacker, "feed_reference", Unpacker_feed_reference, 1);
457
438
  rb_define_method(cMessagePack_Unpacker, "each", Unpacker_each, 0);
@@ -27,36 +27,60 @@ void msgpack_unpacker_ext_registry_static_init()
27
27
  s_dup = rb_intern("dup");
28
28
  }
29
29
 
30
+
30
31
  void msgpack_unpacker_ext_registry_static_destroy()
31
32
  { }
32
33
 
33
- void msgpack_unpacker_ext_registry_init(msgpack_unpacker_ext_registry_t* ukrg)
34
+ void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg)
34
35
  {
35
- for(int i=0; i < 256; i++) {
36
- ukrg->array[i] = Qnil;
36
+ if (ukrg) {
37
+ for(int i=0; i < 256; i++) {
38
+ if (ukrg->array[i] != Qnil) {
39
+ rb_gc_mark(ukrg->array[i]);
40
+ }
41
+ }
37
42
  }
38
43
  }
39
44
 
40
- void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg)
45
+ msgpack_unpacker_ext_registry_t* msgpack_unpacker_ext_registry_cow(msgpack_unpacker_ext_registry_t* src)
41
46
  {
42
- for(int i=0; i < 256; i++) {
43
- rb_gc_mark(ukrg->array[i]);
47
+ msgpack_unpacker_ext_registry_t* dst;
48
+ if (src) {
49
+ if (src->borrow_count) {
50
+ dst = ALLOC(msgpack_unpacker_ext_registry_t);
51
+ dst->borrow_count = 0;
52
+ MEMCPY(dst->array, src->array, VALUE, 256);
53
+ msgpack_unpacker_ext_registry_release(src);
54
+ return dst;
55
+ } else {
56
+ return src;
57
+ }
58
+ } else {
59
+ dst = ALLOC(msgpack_unpacker_ext_registry_t);
60
+ dst->borrow_count = 0;
61
+ for(int i=0; i < 256; i++) {
62
+ dst->array[i] = Qnil;
63
+ }
64
+ return dst;
44
65
  }
45
66
  }
46
67
 
47
- void msgpack_unpacker_ext_registry_dup(msgpack_unpacker_ext_registry_t* src,
48
- msgpack_unpacker_ext_registry_t* dst)
68
+ void msgpack_unpacker_ext_registry_release(msgpack_unpacker_ext_registry_t* ukrg)
49
69
  {
50
- for(int i=0; i < 256; i++) {
51
- dst->array[i] = src->array[i];
70
+ if (ukrg) {
71
+ if (ukrg->borrow_count) {
72
+ ukrg->borrow_count--;
73
+ } else {
74
+ xfree(ukrg);
75
+ }
52
76
  }
53
77
  }
54
78
 
55
- VALUE msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t* ukrg,
56
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg)
79
+ void msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t** ukrg,
80
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg)
57
81
  {
58
- VALUE e = rb_ary_new3(3, ext_module, proc, arg);
59
- VALUE before = ukrg->array[ext_type + 128];
60
- ukrg->array[ext_type + 128] = e;
61
- return before;
82
+ msgpack_unpacker_ext_registry_t* ext_registry = msgpack_unpacker_ext_registry_cow(*ukrg);
83
+
84
+ ext_registry->array[ext_type + 128] = rb_ary_new3(4, ext_module, proc, arg, INT2FIX(flags));
85
+ *ukrg = ext_registry;
62
86
  }