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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yaml +57 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +4 -1
- data/ChangeLog +60 -0
- data/Gemfile +3 -0
- data/README.md +264 -0
- data/Rakefile +1 -9
- data/doclib/msgpack/factory.rb +47 -3
- data/doclib/msgpack/packer.rb +5 -4
- data/doclib/msgpack/time.rb +22 -0
- data/doclib/msgpack/timestamp.rb +44 -0
- data/doclib/msgpack/unpacker.rb +2 -2
- data/ext/java/org/msgpack/jruby/Buffer.java +23 -16
- data/ext/java/org/msgpack/jruby/Decoder.java +46 -23
- data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
- data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +37 -49
- data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
- data/ext/java/org/msgpack/jruby/Factory.java +47 -7
- data/ext/java/org/msgpack/jruby/Packer.java +29 -17
- data/ext/java/org/msgpack/jruby/Unpacker.java +72 -37
- data/ext/msgpack/buffer.c +4 -16
- data/ext/msgpack/buffer.h +46 -5
- data/ext/msgpack/buffer_class.c +23 -15
- data/ext/msgpack/compat.h +1 -12
- data/ext/msgpack/extconf.rb +39 -7
- data/ext/msgpack/factory_class.c +87 -20
- data/ext/msgpack/packer.c +58 -8
- data/ext/msgpack/packer.h +24 -16
- data/ext/msgpack/packer_class.c +29 -31
- data/ext/msgpack/packer_ext_registry.c +22 -30
- data/ext/msgpack/packer_ext_registry.h +38 -31
- data/ext/msgpack/unpacker.c +102 -70
- data/ext/msgpack/unpacker.h +10 -2
- data/ext/msgpack/unpacker_class.c +35 -52
- data/ext/msgpack/unpacker_ext_registry.c +40 -16
- data/ext/msgpack/unpacker_ext_registry.h +21 -14
- data/lib/msgpack/bigint.rb +69 -0
- data/lib/msgpack/factory.rb +103 -0
- data/lib/msgpack/symbol.rb +21 -4
- data/lib/msgpack/time.rb +29 -0
- data/lib/msgpack/timestamp.rb +76 -0
- data/lib/msgpack/version.rb +4 -7
- data/lib/msgpack.rb +8 -12
- data/msgpack.gemspec +3 -7
- data/spec/bigint_spec.rb +26 -0
- data/spec/factory_spec.rb +299 -12
- data/spec/msgpack_spec.rb +1 -1
- data/spec/packer_spec.rb +18 -0
- data/spec/spec_helper.rb +30 -3
- data/spec/timestamp_spec.rb +159 -0
- data/spec/unpacker_spec.rb +135 -4
- metadata +21 -51
- data/.travis.yml +0 -43
- 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
|
-
|
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(
|
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 =
|
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,
|
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,
|
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
|
274
|
+
static VALUE Unpacker_rescue_EOFError(VALUE args, VALUE error)
|
294
275
|
{
|
295
|
-
UNUSED(
|
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
|
-
|
345
|
-
|
346
|
-
|
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
|
34
|
+
void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg)
|
34
35
|
{
|
35
|
-
|
36
|
-
|
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
|
-
|
45
|
+
msgpack_unpacker_ext_registry_t* msgpack_unpacker_ext_registry_cow(msgpack_unpacker_ext_registry_t* src)
|
41
46
|
{
|
42
|
-
|
43
|
-
|
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
|
48
|
-
msgpack_unpacker_ext_registry_t* dst)
|
68
|
+
void msgpack_unpacker_ext_registry_release(msgpack_unpacker_ext_registry_t* ukrg)
|
49
69
|
{
|
50
|
-
|
51
|
-
|
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
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
38
|
+
void msgpack_unpacker_ext_registry_release(msgpack_unpacker_ext_registry_t* ukrg);
|
37
39
|
|
38
|
-
static inline void
|
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
|
44
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
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
|
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
|
data/lib/msgpack/factory.rb
CHANGED
@@ -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
|
data/lib/msgpack/symbol.rb
CHANGED
@@ -1,9 +1,26 @@
|
|
1
1
|
class Symbol
|
2
|
-
|
3
|
-
|
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
|
-
|
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
|
data/lib/msgpack/time.rb
ADDED
@@ -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
|
data/lib/msgpack/version.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
module MessagePack
|
2
|
-
VERSION = "1.
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
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
|