msgpack 1.4.5 → 1.5.6

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +5 -5
  3. data/ChangeLog +32 -0
  4. data/README.md +25 -1
  5. data/bench/bench.rb +78 -0
  6. data/doclib/msgpack/factory.rb +45 -2
  7. data/ext/java/org/msgpack/jruby/Buffer.java +6 -0
  8. data/ext/java/org/msgpack/jruby/Decoder.java +23 -19
  9. data/ext/java/org/msgpack/jruby/Encoder.java +46 -18
  10. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +24 -31
  11. data/ext/java/org/msgpack/jruby/Factory.java +40 -5
  12. data/ext/java/org/msgpack/jruby/Packer.java +21 -11
  13. data/ext/java/org/msgpack/jruby/Unpacker.java +44 -22
  14. data/ext/msgpack/buffer.c +9 -36
  15. data/ext/msgpack/buffer.h +9 -1
  16. data/ext/msgpack/buffer_class.c +18 -9
  17. data/ext/msgpack/compat.h +0 -99
  18. data/ext/msgpack/extconf.rb +9 -11
  19. data/ext/msgpack/factory_class.c +62 -5
  20. data/ext/msgpack/packer.c +42 -29
  21. data/ext/msgpack/packer.h +25 -7
  22. data/ext/msgpack/packer_class.c +23 -20
  23. data/ext/msgpack/packer_ext_registry.c +13 -4
  24. data/ext/msgpack/packer_ext_registry.h +10 -5
  25. data/ext/msgpack/unpacker.c +99 -68
  26. data/ext/msgpack/unpacker.h +10 -6
  27. data/ext/msgpack/unpacker_class.c +16 -8
  28. data/ext/msgpack/unpacker_ext_registry.c +3 -2
  29. data/ext/msgpack/unpacker_ext_registry.h +5 -2
  30. data/lib/msgpack/bigint.rb +69 -0
  31. data/lib/msgpack/factory.rb +103 -0
  32. data/lib/msgpack/version.rb +1 -1
  33. data/lib/msgpack.rb +4 -5
  34. data/msgpack.gemspec +1 -0
  35. data/spec/bigint_spec.rb +26 -0
  36. data/spec/factory_spec.rb +248 -0
  37. data/spec/spec_helper.rb +9 -1
  38. data/spec/timestamp_spec.rb +2 -2
  39. data/spec/unpacker_spec.rb +12 -0
  40. metadata +20 -13
  41. data/bench/pack.rb +0 -23
  42. data/bench/pack_log.rb +0 -33
  43. data/bench/pack_log_long.rb +0 -65
  44. data/bench/pack_symbols.rb +0 -28
  45. data/bench/run.sh +0 -14
  46. data/bench/run_long.sh +0 -35
  47. data/bench/run_symbols.sh +0 -26
  48. data/bench/unpack.rb +0 -21
  49. data/bench/unpack_log.rb +0 -34
  50. data/bench/unpack_log_long.rb +0 -67
@@ -34,6 +34,13 @@ static ID s_call;
34
34
  static msgpack_rmem_t s_stack_rmem;
35
35
  #endif
36
36
 
37
+ #if !defined(HAVE_RB_HASH_NEW_CAPA)
38
+ static inline VALUE rb_hash_new_capa(long capa)
39
+ {
40
+ return rb_hash_new();
41
+ }
42
+ #endif
43
+
37
44
  void msgpack_unpacker_static_init()
38
45
  {
39
46
  #ifdef UNPACKER_STACK_RMEM
@@ -52,6 +59,19 @@ void msgpack_unpacker_static_destroy()
52
59
 
53
60
  #define HEAD_BYTE_REQUIRED 0xc1
54
61
 
62
+ static inline msgpack_unpacker_stack_t* _msgpack_unpacker_new_stack(void) {
63
+ msgpack_unpacker_stack_t *stack = ZALLOC(msgpack_unpacker_stack_t);
64
+ stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
65
+ #ifdef UNPACKER_STACK_RMEM
66
+ stack->data = msgpack_rmem_alloc(&s_stack_rmem);
67
+ /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
68
+ #else
69
+ /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_entry_t));*/
70
+ stack->data = xmalloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_entry_t));
71
+ #endif
72
+ return stack;
73
+ }
74
+
55
75
  msgpack_unpacker_t* _msgpack_unpacker_new(void)
56
76
  {
57
77
  msgpack_unpacker_t* uk = ZALLOC_N(msgpack_unpacker_t, 1);
@@ -63,41 +83,44 @@ msgpack_unpacker_t* _msgpack_unpacker_new(void)
63
83
  uk->last_object = Qnil;
64
84
  uk->reading_raw = Qnil;
65
85
 
66
- #ifdef UNPACKER_STACK_RMEM
67
- uk->stack = msgpack_rmem_alloc(&s_stack_rmem);
68
- /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
69
- #else
70
- /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_t));*/
71
- uk->stack = xmalloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_t));
72
- #endif
73
- uk->stack_capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
86
+ uk->stack = _msgpack_unpacker_new_stack();
74
87
 
75
88
  return uk;
76
89
  }
77
90
 
91
+ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
92
+ #ifdef UNPACKER_STACK_RMEM
93
+ msgpack_rmem_free(&s_stack_rmem, stack->data);
94
+ #else
95
+ xfree(stack->data);
96
+ #endif
97
+ xfree(stack);
98
+ }
99
+
78
100
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
79
101
  {
80
- #ifdef UNPACKER_STACK_RMEM
81
- msgpack_rmem_free(&s_stack_rmem, uk->stack);
82
- #else
83
- xfree(uk->stack);
84
- #endif
85
-
102
+ _msgpack_unpacker_free_stack(uk->stack);
86
103
  msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
87
104
  }
88
105
 
106
+ void msgpack_unpacker_mark_stack(msgpack_unpacker_stack_t* stack)
107
+ {
108
+ while (stack) {
109
+ msgpack_unpacker_stack_entry_t* s = stack->data;
110
+ msgpack_unpacker_stack_entry_t* send = stack->data + stack->depth;
111
+ for(; s < send; s++) {
112
+ rb_gc_mark(s->object);
113
+ rb_gc_mark(s->key);
114
+ }
115
+ stack = stack->parent;
116
+ }
117
+ }
118
+
89
119
  void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
90
120
  {
91
121
  rb_gc_mark(uk->last_object);
92
122
  rb_gc_mark(uk->reading_raw);
93
-
94
- msgpack_unpacker_stack_t* s = uk->stack;
95
- msgpack_unpacker_stack_t* send = uk->stack + uk->stack_depth;
96
- for(; s < send; s++) {
97
- rb_gc_mark(s->object);
98
- rb_gc_mark(s->key);
99
- }
100
-
123
+ msgpack_unpacker_mark_stack(uk->stack);
101
124
  /* See MessagePack_Buffer_wrap */
102
125
  /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
103
126
  rb_gc_mark(uk->buffer_ref);
@@ -109,9 +132,8 @@ void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
109
132
 
110
133
  uk->head_byte = HEAD_BYTE_REQUIRED;
111
134
 
112
- /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack_depth);*/
113
- uk->stack_depth = 0;
114
-
135
+ /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack->depth);*/
136
+ uk->stack->depth = 0;
115
137
  uk->last_object = Qnil;
116
138
  uk->reading_raw = Qnil;
117
139
  uk->reading_raw_remaining = 0;
@@ -163,17 +185,23 @@ static inline int object_complete_symbol(msgpack_unpacker_t* uk, VALUE object)
163
185
  static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
164
186
  {
165
187
  if (uk->optimized_symbol_ext_type && ext_type == uk->symbol_ext_type) {
188
+ if (RB_UNLIKELY(NIL_P(str))) { // empty extension is returned as Qnil
189
+ return object_complete_symbol(uk, ID2SYM(rb_intern3("", 0, rb_utf8_encoding())));
190
+ }
166
191
  return object_complete_symbol(uk, rb_str_intern(str));
167
192
  }
168
193
 
169
- VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type);
194
+ int ext_flags;
195
+ VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type, &ext_flags);
196
+
170
197
  if(proc != Qnil) {
171
- VALUE obj = rb_funcall(proc, s_call, 1, str);
198
+ VALUE obj;
199
+ obj = rb_funcall(proc, s_call, 1, str == Qnil ? rb_str_buf_new(0) : str);
172
200
  return object_complete(uk, obj);
173
201
  }
174
202
 
175
203
  if(uk->allow_unknown_ext) {
176
- VALUE obj = MessagePack_ExtensionValue_new(ext_type, str);
204
+ VALUE obj = MessagePack_ExtensionValue_new(ext_type, str == Qnil ? rb_str_buf_new(0) : str);
177
205
  return object_complete(uk, obj);
178
206
  }
179
207
 
@@ -181,37 +209,37 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
181
209
  }
182
210
 
183
211
  /* stack funcs */
184
- static inline msgpack_unpacker_stack_t* _msgpack_unpacker_stack_top(msgpack_unpacker_t* uk)
212
+ static inline msgpack_unpacker_stack_entry_t* _msgpack_unpacker_stack_entry_top(msgpack_unpacker_t* uk)
185
213
  {
186
- return &uk->stack[uk->stack_depth-1];
214
+ return &uk->stack->data[uk->stack->depth-1];
187
215
  }
188
216
 
189
217
  static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
190
218
  {
191
219
  reset_head_byte(uk);
192
220
 
193
- if(uk->stack_capacity - uk->stack_depth <= 0) {
221
+ if(uk->stack->capacity - uk->stack->depth <= 0) {
194
222
  return PRIMITIVE_STACK_TOO_DEEP;
195
223
  }
196
224
 
197
- msgpack_unpacker_stack_t* next = &uk->stack[uk->stack_depth];
225
+ msgpack_unpacker_stack_entry_t* next = &uk->stack->data[uk->stack->depth];
198
226
  next->count = count;
199
227
  next->type = type;
200
228
  next->object = object;
201
229
  next->key = Qnil;
202
230
 
203
- uk->stack_depth++;
231
+ uk->stack->depth++;
204
232
  return PRIMITIVE_CONTAINER_START;
205
233
  }
206
234
 
207
235
  static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
208
236
  {
209
- return --uk->stack_depth;
237
+ return --uk->stack->depth;
210
238
  }
211
239
 
212
240
  static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
213
241
  {
214
- return uk->stack_depth == 0;
242
+ return uk->stack->depth == 0;
215
243
  }
216
244
 
217
245
  #ifdef USE_CASE_RANGE
@@ -239,8 +267,8 @@ static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
239
267
 
240
268
  static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
241
269
  {
242
- if(uk->stack_depth > 0) {
243
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
270
+ if(uk->stack->depth > 0) {
271
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
244
272
  if(top->type == STACK_TYPE_MAP_KEY) {
245
273
  return true;
246
274
  }
@@ -283,6 +311,30 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
283
311
  {
284
312
  /* assuming uk->reading_raw == Qnil */
285
313
 
314
+ int ext_flags;
315
+ VALUE proc;
316
+
317
+ if(!(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY)) {
318
+ proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, raw_type, &ext_flags);
319
+ if(proc != Qnil && ext_flags & MSGPACK_EXT_RECURSIVE) {
320
+ VALUE obj;
321
+ uk->last_object = Qnil;
322
+ reset_head_byte(uk);
323
+ uk->reading_raw_remaining = 0;
324
+
325
+ msgpack_unpacker_stack_t* child_stack = _msgpack_unpacker_new_stack();
326
+ child_stack->parent = uk->stack;
327
+ uk->stack = child_stack;
328
+
329
+ obj = rb_funcall(proc, s_call, 1, uk->buffer.owner);
330
+
331
+ uk->stack = child_stack->parent;
332
+ _msgpack_unpacker_free_stack(child_stack);
333
+
334
+ return object_complete(uk, obj);
335
+ }
336
+ }
337
+
286
338
  /* try optimized read */
287
339
  size_t length = uk->reading_raw_remaining;
288
340
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
@@ -331,9 +383,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
331
383
 
332
384
  SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr
333
385
  int count = b & 0x1f;
334
- if(count == 0) {
335
- return object_complete(uk, rb_utf8_str_new_static("", 0));
336
- }
337
386
  /* read_raw_body_begin sets uk->reading_raw */
338
387
  uk->reading_raw_remaining = count;
339
388
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -350,7 +399,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
350
399
  if(count == 0) {
351
400
  return object_complete(uk, rb_hash_new());
352
401
  }
353
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
402
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
354
403
 
355
404
  SWITCH_RANGE(b, 0xc0, 0xdf) // Variable
356
405
  switch(b) {
@@ -371,7 +420,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
371
420
  uint8_t length = cb->u8;
372
421
  int ext_type = (signed char) cb->buffer[1];
373
422
  if(length == 0) {
374
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
423
+ return object_complete_ext(uk, ext_type, Qnil);
375
424
  }
376
425
  uk->reading_raw_remaining = length;
377
426
  return read_raw_body_begin(uk, ext_type);
@@ -383,7 +432,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
383
432
  uint16_t length = _msgpack_be16(cb->u16);
384
433
  int ext_type = (signed char) cb->buffer[2];
385
434
  if(length == 0) {
386
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
435
+ return object_complete_ext(uk, ext_type, Qnil);
387
436
  }
388
437
  uk->reading_raw_remaining = length;
389
438
  return read_raw_body_begin(uk, ext_type);
@@ -395,7 +444,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
395
444
  uint32_t length = _msgpack_be32(cb->u32);
396
445
  int ext_type = (signed char) cb->buffer[4];
397
446
  if(length == 0) {
398
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
447
+ return object_complete_ext(uk, ext_type, Qnil);
399
448
  }
400
449
  uk->reading_raw_remaining = length;
401
450
  return read_raw_body_begin(uk, ext_type);
@@ -433,7 +482,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
433
482
  {
434
483
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
435
484
  uint32_t u32 = _msgpack_be32(cb->u32);
436
- return object_complete(uk, ULONG2NUM((unsigned long)u32));
485
+ return object_complete(uk, ULONG2NUM(u32)); // long at least 32 bits
437
486
  }
438
487
 
439
488
  case 0xcf: // unsigned int 64
@@ -461,7 +510,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
461
510
  {
462
511
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
463
512
  int32_t i32 = _msgpack_be32(cb->i32);
464
- return object_complete(uk, LONG2NUM((long)i32));
513
+ return object_complete(uk, LONG2NUM(i32)); // long at least 32 bits
465
514
  }
466
515
 
467
516
  case 0xd3: // signed int 64
@@ -516,9 +565,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
516
565
  {
517
566
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
518
567
  uint8_t count = cb->u8;
519
- if(count == 0) {
520
- return object_complete(uk, rb_utf8_str_new_static("", 0));
521
- }
522
568
  /* read_raw_body_begin sets uk->reading_raw */
523
569
  uk->reading_raw_remaining = count;
524
570
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -528,9 +574,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
528
574
  {
529
575
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
530
576
  uint16_t count = _msgpack_be16(cb->u16);
531
- if(count == 0) {
532
- return object_complete(uk, rb_utf8_str_new_static("", 0));
533
- }
534
577
  /* read_raw_body_begin sets uk->reading_raw */
535
578
  uk->reading_raw_remaining = count;
536
579
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -540,9 +583,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
540
583
  {
541
584
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
542
585
  uint32_t count = _msgpack_be32(cb->u32);
543
- if(count == 0) {
544
- return object_complete(uk, rb_utf8_str_new_static("", 0));
545
- }
546
586
  /* read_raw_body_begin sets uk->reading_raw */
547
587
  uk->reading_raw_remaining = count;
548
588
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -552,9 +592,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
552
592
  {
553
593
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
554
594
  uint8_t count = cb->u8;
555
- if(count == 0) {
556
- return object_complete(uk, rb_str_new_static("", 0));
557
- }
558
595
  /* read_raw_body_begin sets uk->reading_raw */
559
596
  uk->reading_raw_remaining = count;
560
597
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -564,9 +601,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
564
601
  {
565
602
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
566
603
  uint16_t count = _msgpack_be16(cb->u16);
567
- if(count == 0) {
568
- return object_complete(uk, rb_str_new_static("", 0));
569
- }
570
604
  /* read_raw_body_begin sets uk->reading_raw */
571
605
  uk->reading_raw_remaining = count;
572
606
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -576,9 +610,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
576
610
  {
577
611
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
578
612
  uint32_t count = _msgpack_be32(cb->u32);
579
- if(count == 0) {
580
- return object_complete(uk, rb_str_new_static("", 0));
581
- }
582
613
  /* read_raw_body_begin sets uk->reading_raw */
583
614
  uk->reading_raw_remaining = count;
584
615
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -611,7 +642,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
611
642
  if(count == 0) {
612
643
  return object_complete(uk, rb_hash_new());
613
644
  }
614
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
645
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
615
646
  }
616
647
 
617
648
  case 0xdf: // map 32
@@ -621,7 +652,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
621
652
  if(count == 0) {
622
653
  return object_complete(uk, rb_hash_new());
623
654
  }
624
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
655
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
625
656
  }
626
657
 
627
658
  default:
@@ -708,7 +739,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
708
739
 
709
740
  container_completed:
710
741
  {
711
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
742
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
712
743
  switch(top->type) {
713
744
  case STACK_TYPE_ARRAY:
714
745
  rb_ary_push(top->object, uk->last_object);
@@ -758,7 +789,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
758
789
 
759
790
  container_completed:
760
791
  {
761
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
792
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
762
793
 
763
794
  /* this section optimized out */
764
795
  // TODO object_complete still creates objects which should be optimized out
@@ -27,6 +27,7 @@
27
27
 
28
28
  struct msgpack_unpacker_t;
29
29
  typedef struct msgpack_unpacker_t msgpack_unpacker_t;
30
+ typedef struct msgpack_unpacker_stack_t msgpack_unpacker_stack_t;
30
31
 
31
32
  enum stack_type_t {
32
33
  STACK_TYPE_ARRAY,
@@ -39,19 +40,22 @@ typedef struct {
39
40
  enum stack_type_t type;
40
41
  VALUE object;
41
42
  VALUE key;
42
- } msgpack_unpacker_stack_t;
43
+ } msgpack_unpacker_stack_entry_t;
44
+
45
+ struct msgpack_unpacker_stack_t {
46
+ size_t depth;
47
+ size_t capacity;
48
+ msgpack_unpacker_stack_entry_t *data;
49
+ msgpack_unpacker_stack_t *parent;
50
+ };
43
51
 
44
52
  #define MSGPACK_UNPACKER_STACK_SIZE (8+4+8+8) /* assumes size_t <= 64bit, enum <= 32bit, VALUE <= 64bit */
45
53
 
46
54
  struct msgpack_unpacker_t {
47
55
  msgpack_buffer_t buffer;
48
-
56
+ msgpack_unpacker_stack_t *stack;
49
57
  unsigned int head_byte;
50
58
 
51
- msgpack_unpacker_stack_t* stack;
52
- size_t stack_depth;
53
- size_t stack_capacity;
54
-
55
59
  VALUE last_object;
56
60
 
57
61
  VALUE reading_raw;
@@ -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); \
@@ -83,7 +87,7 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
83
87
  } else if(argc == 2) {
84
88
  io = argv[0];
85
89
  options = argv[1];
86
- if(rb_type(options) != T_HASH) {
90
+ if(options != Qnil && rb_type(options) != T_HASH) {
87
91
  rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
88
92
  }
89
93
 
@@ -100,13 +104,13 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
100
104
  if(options != Qnil) {
101
105
  VALUE v;
102
106
 
103
- v = rb_hash_aref(options, ID2SYM(rb_intern("symbolize_keys")));
107
+ v = rb_hash_aref(options, sym_symbolize_keys);
104
108
  msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
105
109
 
106
- v = rb_hash_aref(options, ID2SYM(rb_intern("freeze")));
110
+ v = rb_hash_aref(options, sym_freeze);
107
111
  msgpack_unpacker_set_freeze(uk, RTEST(v));
108
112
 
109
- v = rb_hash_aref(options, ID2SYM(rb_intern("allow_unknown_ext")));
113
+ v = rb_hash_aref(options, sym_allow_unknown_ext);
110
114
  msgpack_unpacker_set_allow_unknown_ext(uk, RTEST(v));
111
115
  }
112
116
 
@@ -143,6 +147,7 @@ NORETURN(static void raise_unpacker_error(int r))
143
147
  case PRIMITIVE_UNEXPECTED_TYPE:
144
148
  rb_raise(eUnexpectedTypeError, "unexpected type");
145
149
  case PRIMITIVE_UNEXPECTED_EXT_TYPE:
150
+ // rb_bug("unexpected extension type");
146
151
  rb_raise(eUnknownExtTypeError, "unexpected extension type");
147
152
  default:
148
153
  rb_raise(eUnpackError, "logically unknown error %d", r);
@@ -204,7 +209,7 @@ static VALUE Unpacker_read_array_header(VALUE self)
204
209
  raise_unpacker_error(r);
205
210
  }
206
211
 
207
- return ULONG2NUM(size);
212
+ return ULONG2NUM(size); // long at least 32 bits
208
213
  }
209
214
 
210
215
  static VALUE Unpacker_read_map_header(VALUE self)
@@ -217,7 +222,7 @@ static VALUE Unpacker_read_map_header(VALUE self)
217
222
  raise_unpacker_error((int)r);
218
223
  }
219
224
 
220
- return ULONG2NUM(size);
225
+ return ULONG2NUM(size); // long at least 32 bits
221
226
  }
222
227
 
223
228
 
@@ -361,7 +366,7 @@ static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
361
366
  rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
362
367
  }
363
368
 
364
- 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);
365
370
 
366
371
  return Qnil;
367
372
  }
@@ -411,6 +416,10 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
411
416
 
412
417
  eUnknownExtTypeError = rb_define_class_under(mMessagePack, "UnknownExtTypeError", eUnpackError);
413
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
+
414
423
  rb_define_alloc_func(cMessagePack_Unpacker, MessagePack_Unpacker_alloc);
415
424
 
416
425
  rb_define_method(cMessagePack_Unpacker, "initialize", MessagePack_Unpacker_initialize, -1);
@@ -441,4 +450,3 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
441
450
 
442
451
  rb_define_method(cMessagePack_Unpacker, "full_unpack", Unpacker_full_unpack, 0);
443
452
  }
444
-
@@ -77,9 +77,10 @@ void msgpack_unpacker_ext_registry_release(msgpack_unpacker_ext_registry_t* ukrg
77
77
  }
78
78
 
79
79
  void msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t** ukrg,
80
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg)
80
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg)
81
81
  {
82
82
  msgpack_unpacker_ext_registry_t* ext_registry = msgpack_unpacker_ext_registry_cow(*ukrg);
83
- ext_registry->array[ext_type + 128] = rb_ary_new3(3, ext_module, proc, arg);
83
+
84
+ ext_registry->array[ext_type + 128] = rb_ary_new3(4, ext_module, proc, arg, INT2FIX(flags));
84
85
  *ukrg = ext_registry;
85
86
  }
@@ -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_unpacker_ext_registry_t;
25
27
  typedef struct msgpack_unpacker_ext_registry_t msgpack_unpacker_ext_registry_t;
26
28
 
@@ -46,14 +48,15 @@ static inline void msgpack_unpacker_ext_registry_borrow(msgpack_unpacker_ext_reg
46
48
  void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg);
47
49
 
48
50
  void msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t** ukrg,
49
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg);
51
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg);
50
52
 
51
53
  static inline VALUE msgpack_unpacker_ext_registry_lookup(msgpack_unpacker_ext_registry_t* ukrg,
52
- int ext_type)
54
+ int ext_type, int* ext_flags_result)
53
55
  {
54
56
  if (ukrg) {
55
57
  VALUE entry = ukrg->array[ext_type + 128];
56
58
  if (entry != Qnil) {
59
+ *ext_flags_result = FIX2INT(rb_ary_entry(entry, 3));
57
60
  return rb_ary_entry(entry, 1);
58
61
  }
59
62
  }
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MessagePack
4
+ module Bigint
5
+ # We split the bigint in 32bits chunks so that individual part fits into
6
+ # a MRI immediate Integer.
7
+ CHUNK_BITLENGTH = 32
8
+ FORMAT = 'CL>*'
9
+
10
+ if Integer.instance_method(:[]).arity != 1 # Ruby 2.7 and newer
11
+ # Starting from Ruby 2.7 we can address arbitrary bitranges inside an Integer with Integer#[]
12
+ # This allows to not allocate any Integer.
13
+ def self.to_msgpack_ext(bigint)
14
+ members = []
15
+
16
+ if bigint < 0
17
+ bigint = -bigint
18
+ members << 1
19
+ else
20
+ members << 0
21
+ end
22
+
23
+ offset = 0
24
+ length = bigint.bit_length
25
+ while offset < length
26
+ members << bigint[offset, CHUNK_BITLENGTH]
27
+ offset += CHUNK_BITLENGTH
28
+ end
29
+
30
+ members.pack(FORMAT)
31
+ end
32
+ else
33
+ # On 2.6 and older since we can't address arbitrary bitranges, so we fallback to shifting the bigint.
34
+ # This means that after each shift, we may allocate another Integer instance.
35
+ BASE = (2**CHUNK_BITLENGTH) - 1
36
+ def self.to_msgpack_ext(bigint)
37
+ members = []
38
+
39
+ if bigint < 0
40
+ bigint = -bigint
41
+ members << 1
42
+ else
43
+ members << 0
44
+ end
45
+
46
+ while bigint > 0
47
+ members << (bigint & BASE)
48
+ bigint = bigint >> CHUNK_BITLENGTH
49
+ end
50
+
51
+ members.pack(FORMAT)
52
+ end
53
+ end
54
+
55
+ def self.from_msgpack_ext(data)
56
+ parts = data.unpack(FORMAT)
57
+
58
+ sign = parts.shift
59
+ sum = parts.pop.to_i
60
+
61
+ parts.reverse_each do |part|
62
+ sum = sum << CHUNK_BITLENGTH
63
+ sum += part
64
+ end
65
+
66
+ sign == 0 ? sum : -sum
67
+ end
68
+ end
69
+ end