msgpack 1.4.5 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -52,6 +52,16 @@ void msgpack_unpacker_static_destroy()
52
52
 
53
53
  #define HEAD_BYTE_REQUIRED 0xc1
54
54
 
55
+ static inline msgpack_unpacker_stack_t* _msgpack_unpacker_new_stack(void) {
56
+ #ifdef UNPACKER_STACK_RMEM
57
+ return msgpack_rmem_alloc(&s_stack_rmem);
58
+ /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
59
+ #else
60
+ /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_t));*/
61
+ return xmalloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_t));
62
+ #endif
63
+ }
64
+
55
65
  msgpack_unpacker_t* _msgpack_unpacker_new(void)
56
66
  {
57
67
  msgpack_unpacker_t* uk = ZALLOC_N(msgpack_unpacker_t, 1);
@@ -63,26 +73,23 @@ msgpack_unpacker_t* _msgpack_unpacker_new(void)
63
73
  uk->last_object = Qnil;
64
74
  uk->reading_raw = Qnil;
65
75
 
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
76
+ uk->stack = _msgpack_unpacker_new_stack();
73
77
  uk->stack_capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
74
78
 
75
79
  return uk;
76
80
  }
77
81
 
82
+ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
83
+ #ifdef UNPACKER_STACK_RMEM
84
+ msgpack_rmem_free(&s_stack_rmem, stack);
85
+ #else
86
+ xfree(stack);
87
+ #endif
88
+ }
89
+
78
90
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
79
91
  {
80
- #ifdef UNPACKER_STACK_RMEM
81
- msgpack_rmem_free(&s_stack_rmem, uk->stack);
82
- #else
83
- xfree(uk->stack);
84
- #endif
85
-
92
+ _msgpack_unpacker_free_stack(uk->stack);
86
93
  msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
87
94
  }
88
95
 
@@ -166,14 +173,17 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
166
173
  return object_complete_symbol(uk, rb_str_intern(str));
167
174
  }
168
175
 
169
- VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type);
176
+ int ext_flags;
177
+ VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type, &ext_flags);
178
+
170
179
  if(proc != Qnil) {
171
- VALUE obj = rb_funcall(proc, s_call, 1, str);
180
+ VALUE obj;
181
+ obj = rb_funcall(proc, s_call, 1, str == Qnil ? rb_str_buf_new(0) : str);
172
182
  return object_complete(uk, obj);
173
183
  }
174
184
 
175
185
  if(uk->allow_unknown_ext) {
176
- VALUE obj = MessagePack_ExtensionValue_new(ext_type, str);
186
+ VALUE obj = MessagePack_ExtensionValue_new(ext_type, str == Qnil ? rb_str_buf_new(0) : str);
177
187
  return object_complete(uk, obj);
178
188
  }
179
189
 
@@ -283,6 +293,36 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
283
293
  {
284
294
  /* assuming uk->reading_raw == Qnil */
285
295
 
296
+ int ext_flags;
297
+ VALUE proc;
298
+
299
+ if(!(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY)) {
300
+ proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, raw_type, &ext_flags);
301
+ if(proc != Qnil && ext_flags & MSGPACK_EXT_RECURSIVE) {
302
+ VALUE obj;
303
+ uk->last_object = Qnil;
304
+ reset_head_byte(uk);
305
+ uk->reading_raw_remaining = 0;
306
+
307
+ msgpack_unpacker_stack_t* stack = uk->stack;
308
+ size_t stack_depth = uk->stack_depth;
309
+ size_t stack_capacity = uk->stack_capacity;
310
+
311
+ uk->stack = _msgpack_unpacker_new_stack();
312
+ uk->stack_depth = 0;
313
+ uk->stack_capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
314
+
315
+ obj = rb_funcall(proc, s_call, 1, uk->buffer.owner);
316
+
317
+ _msgpack_unpacker_free_stack(uk->stack);
318
+ uk->stack = stack;
319
+ uk->stack_depth = stack_depth;
320
+ uk->stack_capacity = stack_capacity;
321
+
322
+ return object_complete(uk, obj);
323
+ }
324
+ }
325
+
286
326
  /* try optimized read */
287
327
  size_t length = uk->reading_raw_remaining;
288
328
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
@@ -371,7 +411,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
371
411
  uint8_t length = cb->u8;
372
412
  int ext_type = (signed char) cb->buffer[1];
373
413
  if(length == 0) {
374
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
414
+ return object_complete_ext(uk, ext_type, Qnil);
375
415
  }
376
416
  uk->reading_raw_remaining = length;
377
417
  return read_raw_body_begin(uk, ext_type);
@@ -383,7 +423,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
383
423
  uint16_t length = _msgpack_be16(cb->u16);
384
424
  int ext_type = (signed char) cb->buffer[2];
385
425
  if(length == 0) {
386
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
426
+ return object_complete_ext(uk, ext_type, Qnil);
387
427
  }
388
428
  uk->reading_raw_remaining = length;
389
429
  return read_raw_body_begin(uk, ext_type);
@@ -395,7 +435,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
395
435
  uint32_t length = _msgpack_be32(cb->u32);
396
436
  int ext_type = (signed char) cb->buffer[4];
397
437
  if(length == 0) {
398
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
438
+ return object_complete_ext(uk, ext_type, Qnil);
399
439
  }
400
440
  uk->reading_raw_remaining = length;
401
441
  return read_raw_body_begin(uk, ext_type);
@@ -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);
@@ -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);
@@ -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
@@ -77,5 +77,108 @@ module MessagePack
77
77
  packer.full_pack
78
78
  end
79
79
  alias :pack :dump
80
+
81
+ def pool(size = 1, **options)
82
+ Pool.new(
83
+ frozen? ? self : dup.freeze,
84
+ size,
85
+ options.empty? ? nil : options,
86
+ )
87
+ end
88
+
89
+ class Pool
90
+ if RUBY_ENGINE == "ruby"
91
+ class AbstractPool
92
+ def initialize(size, &block)
93
+ @size = size
94
+ @new_member = block
95
+ @members = []
96
+ end
97
+
98
+ def checkout
99
+ @members.pop || @new_member.call
100
+ end
101
+
102
+ def checkin(member)
103
+ # If the pool is already full, we simply drop the extra member.
104
+ # This is because contrary to a connection pool, creating an extra instance
105
+ # is extremely unlikely to cause some kind of resource exhaustion.
106
+ #
107
+ # We could cycle the members (keep the newer one) but first It's more work and second
108
+ # the older member might have been created pre-fork, so it might be at least partially
109
+ # in shared memory.
110
+ if member && @members.size < @size
111
+ member.reset
112
+ @members << member
113
+ end
114
+ end
115
+ end
116
+ else
117
+ class AbstractPool
118
+ def initialize(size, &block)
119
+ @size = size
120
+ @new_member = block
121
+ @members = []
122
+ @mutex = Mutex.new
123
+ end
124
+
125
+ def checkout
126
+ @mutex.synchronize { @members.pop } || @new_member.call
127
+ end
128
+
129
+ def checkin(member)
130
+ @mutex.synchronize do
131
+ if member && @members.size < @size
132
+ member.reset
133
+ @members << member
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ class PackerPool < AbstractPool
141
+ private
142
+
143
+ def reset(packer)
144
+ packer.clear
145
+ end
146
+ end
147
+
148
+ class UnpackerPool < AbstractPool
149
+ private
150
+
151
+ def reset(unpacker)
152
+ unpacker.reset
153
+ end
154
+ end
155
+
156
+ def initialize(factory, size, options = nil)
157
+ options = nil if !options || options.empty?
158
+ @factory = factory
159
+ @packers = PackerPool.new(size) { factory.packer(options) }
160
+ @unpackers = UnpackerPool.new(size) { factory.unpacker(options) }
161
+ end
162
+
163
+ def load(data)
164
+ unpacker = @unpackers.checkout
165
+ begin
166
+ unpacker.feed_reference(data)
167
+ unpacker.full_unpack
168
+ ensure
169
+ @unpackers.checkin(unpacker)
170
+ end
171
+ end
172
+
173
+ def dump(object)
174
+ packer = @packers.checkout
175
+ begin
176
+ packer.write(object)
177
+ packer.full_pack
178
+ ensure
179
+ @packers.checkin(packer)
180
+ end
181
+ end
182
+ end
80
183
  end
81
184
  end
@@ -1,5 +1,5 @@
1
1
  module MessagePack
2
- VERSION = "1.4.5"
2
+ VERSION = "1.5.2"
3
3
  # Note for maintainers:
4
4
  # Don't miss building/releasing the JRuby version (rake buld:java)
5
5
  # See "How to build -java rubygems" in README for more details.
data/lib/msgpack.rb CHANGED
@@ -17,16 +17,15 @@ require "msgpack/time"
17
17
 
18
18
  module MessagePack
19
19
  DefaultFactory = MessagePack::Factory.new
20
- DEFAULT_EMPTY_PARAMS = {}.freeze
21
20
 
22
21
  def load(src, param = nil)
23
22
  unpacker = nil
24
23
 
25
24
  if src.is_a? String
26
- unpacker = DefaultFactory.unpacker param || DEFAULT_EMPTY_PARAMS
25
+ unpacker = DefaultFactory.unpacker param
27
26
  unpacker.feed_reference src
28
27
  else
29
- unpacker = DefaultFactory.unpacker src, param || DEFAULT_EMPTY_PARAMS
28
+ unpacker = DefaultFactory.unpacker src, param
30
29
  end
31
30
 
32
31
  unpacker.full_unpack
@@ -36,8 +35,8 @@ module MessagePack
36
35
  module_function :load
37
36
  module_function :unpack
38
37
 
39
- def pack(v, *rest)
40
- packer = DefaultFactory.packer(*rest)
38
+ def pack(v, io = nil, options = nil)
39
+ packer = DefaultFactory.packer(io, options)
41
40
  packer.write v
42
41
  packer.full_pack
43
42
  end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe MessagePack::Bigint do
4
+ it 'serialize and deserialize arbitrary sized integer' do
5
+ [
6
+ 1,
7
+ -1,
8
+ 120938120391283122132313,
9
+ -21903120391203912391023920332103,
10
+ 210290021321301203912933021323,
11
+ ].each do |int|
12
+ expect(MessagePack::Bigint.from_msgpack_ext(MessagePack::Bigint.to_msgpack_ext(int))).to be == int
13
+ end
14
+ end
15
+
16
+ it 'has a stable format' do
17
+ {
18
+ 120938120391283122132313 => "\x00\x9F\xF4UY\x11\x92\x9A?\x00\x00\x19\x9C".b,
19
+ -21903120391203912391023920332103 => "\x01/\xB2\xBDG\xBD\xDE\xAA\xEBt\xCC\x8A\xC1\x00\x00\x01\x14".b,
20
+ 210290021321301203912933021323 => "\x00\xC4\xD8\x96\x8Bm\xCB\xC7\x03\xA7{\xD4\"\x00\x00\x00\x02".b,
21
+ }.each do |int, payload|
22
+ expect(MessagePack::Bigint.to_msgpack_ext(int)).to be == payload
23
+ expect(MessagePack::Bigint.from_msgpack_ext(payload)).to be == int
24
+ end
25
+ end
26
+ end