msgpack 1.2.10 → 1.5.1

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +57 -0
  3. data/.gitignore +3 -1
  4. data/.rubocop.yml +4 -1
  5. data/ChangeLog +60 -0
  6. data/Gemfile +3 -0
  7. data/README.md +264 -0
  8. data/Rakefile +1 -9
  9. data/doclib/msgpack/factory.rb +47 -3
  10. data/doclib/msgpack/packer.rb +5 -4
  11. data/doclib/msgpack/time.rb +22 -0
  12. data/doclib/msgpack/timestamp.rb +44 -0
  13. data/doclib/msgpack/unpacker.rb +2 -2
  14. data/ext/java/org/msgpack/jruby/Buffer.java +23 -16
  15. data/ext/java/org/msgpack/jruby/Decoder.java +46 -23
  16. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  17. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +37 -49
  18. data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
  19. data/ext/java/org/msgpack/jruby/Factory.java +47 -7
  20. data/ext/java/org/msgpack/jruby/Packer.java +29 -17
  21. data/ext/java/org/msgpack/jruby/Unpacker.java +72 -37
  22. data/ext/msgpack/buffer.c +4 -16
  23. data/ext/msgpack/buffer.h +46 -5
  24. data/ext/msgpack/buffer_class.c +23 -15
  25. data/ext/msgpack/compat.h +1 -12
  26. data/ext/msgpack/extconf.rb +39 -7
  27. data/ext/msgpack/factory_class.c +87 -20
  28. data/ext/msgpack/packer.c +58 -8
  29. data/ext/msgpack/packer.h +24 -16
  30. data/ext/msgpack/packer_class.c +29 -31
  31. data/ext/msgpack/packer_ext_registry.c +22 -30
  32. data/ext/msgpack/packer_ext_registry.h +38 -31
  33. data/ext/msgpack/unpacker.c +102 -70
  34. data/ext/msgpack/unpacker.h +10 -2
  35. data/ext/msgpack/unpacker_class.c +35 -52
  36. data/ext/msgpack/unpacker_ext_registry.c +40 -16
  37. data/ext/msgpack/unpacker_ext_registry.h +21 -14
  38. data/lib/msgpack/bigint.rb +69 -0
  39. data/lib/msgpack/factory.rb +103 -0
  40. data/lib/msgpack/symbol.rb +21 -4
  41. data/lib/msgpack/time.rb +29 -0
  42. data/lib/msgpack/timestamp.rb +76 -0
  43. data/lib/msgpack/version.rb +4 -7
  44. data/lib/msgpack.rb +8 -12
  45. data/msgpack.gemspec +3 -7
  46. data/spec/bigint_spec.rb +26 -0
  47. data/spec/factory_spec.rb +299 -12
  48. data/spec/msgpack_spec.rb +1 -1
  49. data/spec/packer_spec.rb +18 -0
  50. data/spec/spec_helper.rb +30 -3
  51. data/spec/timestamp_spec.rb +159 -0
  52. data/spec/unpacker_spec.rb +135 -4
  53. metadata +21 -51
  54. data/.travis.yml +0 -43
  55. data/README.rdoc +0 -209
@@ -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;
@@ -77,9 +80,6 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
77
80
  VALUE v = argv[0];
78
81
  if(rb_type(v) == T_HASH) {
79
82
  options = v;
80
- if(rb_type(options) != T_HASH) {
81
- rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
82
- }
83
83
  } else {
84
84
  io = v;
85
85
  }
@@ -87,7 +87,7 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
87
87
  } else if(argc == 2) {
88
88
  io = argv[0];
89
89
  options = argv[1];
90
- if(rb_type(options) != T_HASH) {
90
+ if(options != Qnil && rb_type(options) != T_HASH) {
91
91
  rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
92
92
  }
93
93
 
@@ -97,7 +97,6 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
97
97
 
98
98
  UNPACKER(self, uk);
99
99
 
100
- msgpack_unpacker_ext_registry_init(&uk->ext_registry);
101
100
  uk->buffer_ref = MessagePack_Buffer_wrap(UNPACKER_BUFFER_(uk), self);
102
101
 
103
102
  MessagePack_Buffer_set_options(UNPACKER_BUFFER_(uk), io, options);
@@ -105,10 +104,13 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
105
104
  if(options != Qnil) {
106
105
  VALUE v;
107
106
 
108
- v = rb_hash_aref(options, ID2SYM(rb_intern("symbolize_keys")));
107
+ v = rb_hash_aref(options, sym_symbolize_keys);
109
108
  msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
110
109
 
111
- v = rb_hash_aref(options, ID2SYM(rb_intern("allow_unknown_ext")));
110
+ v = rb_hash_aref(options, sym_freeze);
111
+ msgpack_unpacker_set_freeze(uk, RTEST(v));
112
+
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
 
@@ -121,13 +123,19 @@ static VALUE Unpacker_symbolized_keys_p(VALUE self)
121
123
  return uk->symbolize_keys ? Qtrue : Qfalse;
122
124
  }
123
125
 
126
+ static VALUE Unpacker_freeze_p(VALUE self)
127
+ {
128
+ UNPACKER(self, uk);
129
+ return uk->freeze ? Qtrue : Qfalse;
130
+ }
131
+
124
132
  static VALUE Unpacker_allow_unknown_ext_p(VALUE self)
125
133
  {
126
134
  UNPACKER(self, uk);
127
135
  return uk->allow_unknown_ext ? Qtrue : Qfalse;
128
136
  }
129
137
 
130
- static void raise_unpacker_error(int r)
138
+ NORETURN(static void raise_unpacker_error(int r))
131
139
  {
132
140
  switch(r) {
133
141
  case PRIMITIVE_EOF:
@@ -139,6 +147,7 @@ static void raise_unpacker_error(int r)
139
147
  case PRIMITIVE_UNEXPECTED_TYPE:
140
148
  rb_raise(eUnexpectedTypeError, "unexpected type");
141
149
  case PRIMITIVE_UNEXPECTED_EXT_TYPE:
150
+ // rb_bug("unexpected extension type");
142
151
  rb_raise(eUnknownExtTypeError, "unexpected extension type");
143
152
  default:
144
153
  rb_raise(eUnpackError, "logically unknown error %d", r);
@@ -216,34 +225,6 @@ static VALUE Unpacker_read_map_header(VALUE self)
216
225
  return ULONG2NUM(size);
217
226
  }
218
227
 
219
- static VALUE Unpacker_peek_next_type(VALUE self)
220
- {
221
- UNPACKER(self, uk);
222
-
223
- int r = msgpack_unpacker_peek_next_object_type(uk);
224
- if(r < 0) {
225
- raise_unpacker_error(r);
226
- }
227
-
228
- switch((enum msgpack_unpacker_object_type) r) {
229
- case TYPE_NIL:
230
- return rb_intern("nil");
231
- case TYPE_BOOLEAN:
232
- return rb_intern("boolean");
233
- case TYPE_INTEGER:
234
- return rb_intern("integer");
235
- case TYPE_FLOAT:
236
- return rb_intern("float");
237
- case TYPE_RAW:
238
- return rb_intern("raw");
239
- case TYPE_ARRAY:
240
- return rb_intern("array");
241
- case TYPE_MAP:
242
- return rb_intern("map");
243
- default:
244
- rb_raise(eUnpackError, "logically unknown type %d", r);
245
- }
246
- }
247
228
 
248
229
  static VALUE Unpacker_feed(VALUE self, VALUE data)
249
230
  {
@@ -290,9 +271,10 @@ static VALUE Unpacker_each_impl(VALUE self)
290
271
  }
291
272
  }
292
273
 
293
- static VALUE Unpacker_rescue_EOFError(VALUE self)
274
+ static VALUE Unpacker_rescue_EOFError(VALUE args, VALUE error)
294
275
  {
295
- UNUSED(self);
276
+ UNUSED(args);
277
+ UNUSED(error);
296
278
  return Qnil;
297
279
  }
298
280
 
@@ -341,9 +323,11 @@ static VALUE Unpacker_registered_types_internal(VALUE self)
341
323
  UNPACKER(self, uk);
342
324
 
343
325
  VALUE mapping = rb_hash_new();
344
- for(int i=0; i < 256; i++) {
345
- if(uk->ext_registry.array[i] != Qnil) {
346
- 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
+ }
347
331
  }
348
332
  }
349
333
 
@@ -363,12 +347,7 @@ static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
363
347
  case 1:
364
348
  /* register_type(0x7f) {|data| block... } */
365
349
  rb_need_block();
366
- #ifdef HAVE_RB_BLOCK_LAMBDA
367
350
  proc = rb_block_lambda();
368
- #else
369
- /* MRI 1.8 */
370
- proc = rb_block_proc();
371
- #endif
372
351
  arg = proc;
373
352
  ext_module = Qnil;
374
353
  break;
@@ -387,7 +366,7 @@ static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
387
366
  rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
388
367
  }
389
368
 
390
- 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);
391
370
 
392
371
  return Qnil;
393
372
  }
@@ -437,10 +416,15 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
437
416
 
438
417
  eUnknownExtTypeError = rb_define_class_under(mMessagePack, "UnknownExtTypeError", eUnpackError);
439
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
+
440
423
  rb_define_alloc_func(cMessagePack_Unpacker, MessagePack_Unpacker_alloc);
441
424
 
442
425
  rb_define_method(cMessagePack_Unpacker, "initialize", MessagePack_Unpacker_initialize, -1);
443
426
  rb_define_method(cMessagePack_Unpacker, "symbolize_keys?", Unpacker_symbolized_keys_p, 0);
427
+ rb_define_method(cMessagePack_Unpacker, "freeze?", Unpacker_freeze_p, 0);
444
428
  rb_define_method(cMessagePack_Unpacker, "allow_unknown_ext?", Unpacker_allow_unknown_ext_p, 0);
445
429
  rb_define_method(cMessagePack_Unpacker, "buffer", Unpacker_buffer, 0);
446
430
  rb_define_method(cMessagePack_Unpacker, "read", Unpacker_read, 0);
@@ -449,7 +433,6 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
449
433
  rb_define_method(cMessagePack_Unpacker, "skip_nil", Unpacker_skip_nil, 0);
450
434
  rb_define_method(cMessagePack_Unpacker, "read_array_header", Unpacker_read_array_header, 0);
451
435
  rb_define_method(cMessagePack_Unpacker, "read_map_header", Unpacker_read_map_header, 0);
452
- //rb_define_method(cMessagePack_Unpacker, "peek_next_type", Unpacker_peek_next_type, 0); // TODO
453
436
  rb_define_method(cMessagePack_Unpacker, "feed", Unpacker_feed, 1);
454
437
  rb_define_method(cMessagePack_Unpacker, "feed_reference", Unpacker_feed_reference, 1);
455
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
  }
@@ -21,39 +21,46 @@
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
 
27
29
  struct msgpack_unpacker_ext_registry_t {
30
+ unsigned int borrow_count;
28
31
  VALUE array[256];
29
- //int bitmap;
30
32
  };
31
33
 
32
34
  void msgpack_unpacker_ext_registry_static_init();
33
35
 
34
36
  void msgpack_unpacker_ext_registry_static_destroy();
35
37
 
36
- void msgpack_unpacker_ext_registry_init(msgpack_unpacker_ext_registry_t* ukrg);
38
+ void msgpack_unpacker_ext_registry_release(msgpack_unpacker_ext_registry_t* ukrg);
37
39
 
38
- static inline void msgpack_unpacker_ext_registry_destroy(msgpack_unpacker_ext_registry_t* ukrg)
39
- { }
40
+ static inline void msgpack_unpacker_ext_registry_borrow(msgpack_unpacker_ext_registry_t* src, msgpack_unpacker_ext_registry_t** dst)
41
+ {
42
+ if (src) {
43
+ src->borrow_count++;
44
+ *dst = src;
45
+ }
46
+ }
40
47
 
41
48
  void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg);
42
49
 
43
- void msgpack_unpacker_ext_registry_dup(msgpack_unpacker_ext_registry_t* src,
44
- msgpack_unpacker_ext_registry_t* dst);
45
-
46
- VALUE msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t* ukrg,
47
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg);
50
+ void msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t** ukrg,
51
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg);
48
52
 
49
53
  static inline VALUE msgpack_unpacker_ext_registry_lookup(msgpack_unpacker_ext_registry_t* ukrg,
50
- int ext_type)
54
+ int ext_type, int* ext_flags_result)
51
55
  {
52
- VALUE e = ukrg->array[ext_type + 128];
53
- if(e == Qnil) {
54
- return Qnil;
56
+ if (ukrg) {
57
+ VALUE entry = ukrg->array[ext_type + 128];
58
+ if (entry != Qnil) {
59
+ *ext_flags_result = FIX2INT(rb_ary_entry(entry, 3));
60
+ return rb_ary_entry(entry, 1);
61
+ }
55
62
  }
56
- return rb_ary_entry(e, 1);
63
+ return Qnil;
57
64
  }
58
65
 
59
66
  #endif
@@ -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,9 +1,26 @@
1
1
  class Symbol
2
- def to_msgpack_ext
3
- [to_s].pack('A*')
2
+ # to_msgpack_ext is supposed to return a binary string.
3
+ # The canonical way to do it for symbols would be:
4
+ # [to_s].pack('A*')
5
+ # However in this instance we can take a shortcut
6
+ if method_defined?(:name)
7
+ alias_method :to_msgpack_ext, :name
8
+ else
9
+ alias_method :to_msgpack_ext, :to_s
4
10
  end
5
11
 
6
12
  def self.from_msgpack_ext(data)
7
- data.unpack('A*').first.to_sym
13
+ # from_msgpack_ext is supposed to parse a binary string.
14
+ # The canonical way to do it for symbols would be:
15
+ # data.unpack1('A*').to_sym
16
+ # However in this instance we can take a shortcut
17
+
18
+ # We assume the string encoding is UTF-8, and let Ruby create either
19
+ # an ASCII symbol or UTF-8 symbol.
20
+ data.force_encoding(Encoding::UTF_8).to_sym
21
+ rescue EncodingError
22
+ # If somehow the string wasn't valid UTF-8 not valid ASCII, we fallback
23
+ # to what has been the historical behavior of creating a binary symbol
24
+ data.force_encoding(Encoding::BINARY).to_sym
8
25
  end
9
- end
26
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # MessagePack extention packer and unpacker for built-in Time class
4
+ module MessagePack
5
+ module Time
6
+ # 3-arg Time.at is available Ruby >= 2.5
7
+ TIME_AT_3_AVAILABLE = begin
8
+ !!::Time.at(0, 0, :nanosecond)
9
+ rescue ArgumentError
10
+ false
11
+ end
12
+
13
+ Unpacker = if TIME_AT_3_AVAILABLE
14
+ lambda do |payload|
15
+ tv = MessagePack::Timestamp.from_msgpack_ext(payload)
16
+ ::Time.at(tv.sec, tv.nsec, :nanosecond)
17
+ end
18
+ else
19
+ lambda do |payload|
20
+ tv = MessagePack::Timestamp.from_msgpack_ext(payload)
21
+ ::Time.at(tv.sec, tv.nsec / 1000.0r)
22
+ end
23
+ end
24
+
25
+ Packer = lambda { |time|
26
+ MessagePack::Timestamp.to_msgpack_ext(time.tv_sec, time.tv_nsec)
27
+ }
28
+ end
29
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MessagePack
4
+ class Timestamp # a.k.a. "TimeSpec"
5
+ # Because the byte-order of MessagePack is big-endian in,
6
+ # pack() and unpack() specifies ">".
7
+ # See https://docs.ruby-lang.org/en/trunk/Array.html#method-i-pack for details.
8
+
9
+ # The timestamp extension type defined in the MessagePack spec.
10
+ # See https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type for details.
11
+ TYPE = -1
12
+
13
+ TIMESTAMP32_MAX_SEC = (1 << 32) - 1
14
+ TIMESTAMP64_MAX_SEC = (1 << 34) - 1
15
+
16
+ # @return [Integer]
17
+ attr_reader :sec
18
+
19
+ # @return [Integer]
20
+ attr_reader :nsec
21
+
22
+ # @param [Integer] sec
23
+ # @param [Integer] nsec
24
+ def initialize(sec, nsec)
25
+ @sec = sec
26
+ @nsec = nsec
27
+ end
28
+
29
+ def self.from_msgpack_ext(data)
30
+ case data.length
31
+ when 4
32
+ # timestamp32 (sec: uint32be)
33
+ sec, = data.unpack('L>')
34
+ new(sec, 0)
35
+ when 8
36
+ # timestamp64 (nsec: uint30be, sec: uint34be)
37
+ n, s = data.unpack('L>2')
38
+ sec = ((n & 0b11) << 32) | s
39
+ nsec = n >> 2
40
+ new(sec, nsec)
41
+ when 12
42
+ # timestam96 (nsec: uint32be, sec: int64be)
43
+ nsec, sec = data.unpack('L>q>')
44
+ new(sec, nsec)
45
+ else
46
+ raise MalformedFormatError, "Invalid timestamp data size: #{data.length}"
47
+ end
48
+ end
49
+
50
+ def self.to_msgpack_ext(sec, nsec)
51
+ if sec >= 0 && nsec >= 0 && sec <= TIMESTAMP64_MAX_SEC
52
+ if nsec === 0 && sec <= TIMESTAMP32_MAX_SEC
53
+ # timestamp32 = (sec: uint32be)
54
+ [sec].pack('L>')
55
+ else
56
+ # timestamp64 (nsec: uint30be, sec: uint34be)
57
+ nsec30 = nsec << 2
58
+ sec_high2 = sec >> 32 # high 2 bits (`x & 0b11` is redandunt)
59
+ sec_low32 = sec & 0xffffffff # low 32 bits
60
+ [nsec30 | sec_high2, sec_low32].pack('L>2')
61
+ end
62
+ else
63
+ # timestamp96 (nsec: uint32be, sec: int64be)
64
+ [nsec, sec].pack('L>q>')
65
+ end
66
+ end
67
+
68
+ def to_msgpack_ext
69
+ self.class.to_msgpack_ext(sec, nsec)
70
+ end
71
+
72
+ def ==(other)
73
+ other.class == self.class && sec == other.sec && nsec == other.nsec
74
+ end
75
+ end
76
+ end
@@ -1,9 +1,6 @@
1
1
  module MessagePack
2
- VERSION = "1.2.10"
3
-
4
- # NOTE for msgpack-ruby maintainer:
5
- # Check these things to release new binaryes for new Ruby versions (especially for Windows):
6
- # * versions/supports of rake-compiler & rake-compiler-dock
7
- # * update RUBY_CC_VERSION in Rakefile
8
- # * check Ruby dependency of released mswin gem details
2
+ VERSION = "1.5.1"
3
+ # Note for maintainers:
4
+ # Don't miss building/releasing the JRuby version (rake buld:java)
5
+ # See "How to build -java rubygems" in README for more details.
9
6
  end