msgpack 1.4.3 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }