msgpack 1.2.9 → 1.4.4
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 +56 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +4 -1
- data/ChangeLog +46 -0
- data/Gemfile +3 -0
- data/README.md +242 -0
- data/Rakefile +1 -9
- data/doclib/msgpack/factory.rb +1 -0
- data/doclib/msgpack/time.rb +22 -0
- data/doclib/msgpack/timestamp.rb +44 -0
- data/ext/java/org/msgpack/jruby/Buffer.java +17 -16
- data/ext/java/org/msgpack/jruby/Decoder.java +29 -10
- data/ext/java/org/msgpack/jruby/Encoder.java +22 -12
- data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +9 -9
- data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
- data/ext/java/org/msgpack/jruby/Factory.java +7 -2
- data/ext/java/org/msgpack/jruby/Packer.java +11 -9
- data/ext/java/org/msgpack/jruby/Unpacker.java +40 -27
- data/ext/msgpack/buffer.c +4 -16
- data/ext/msgpack/buffer.h +60 -5
- data/ext/msgpack/compat.h +1 -12
- data/ext/msgpack/extconf.rb +39 -7
- data/ext/msgpack/factory_class.c +10 -5
- data/ext/msgpack/packer.c +18 -5
- data/ext/msgpack/packer.h +0 -16
- data/ext/msgpack/packer_class.c +0 -9
- data/ext/msgpack/packer_ext_registry.c +0 -22
- data/ext/msgpack/unpacker.c +41 -49
- data/ext/msgpack/unpacker.h +8 -0
- data/ext/msgpack/unpacker_class.c +23 -13
- data/lib/msgpack/symbol.rb +14 -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 +5 -8
- data/msgpack.gemspec +3 -7
- data/spec/factory_spec.rb +17 -0
- data/spec/msgpack_spec.rb +1 -1
- data/spec/packer_spec.rb +18 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/timestamp_spec.rb +161 -0
- data/spec/unpacker_spec.rb +113 -1
- metadata +19 -51
- data/.travis.yml +0 -41
- data/README.rdoc +0 -209
|
@@ -77,9 +77,6 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
|
|
|
77
77
|
VALUE v = argv[0];
|
|
78
78
|
if(rb_type(v) == T_HASH) {
|
|
79
79
|
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
80
|
} else {
|
|
84
81
|
io = v;
|
|
85
82
|
}
|
|
@@ -108,6 +105,9 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
|
|
|
108
105
|
v = rb_hash_aref(options, ID2SYM(rb_intern("symbolize_keys")));
|
|
109
106
|
msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
|
|
110
107
|
|
|
108
|
+
v = rb_hash_aref(options, ID2SYM(rb_intern("freeze")));
|
|
109
|
+
msgpack_unpacker_set_freeze(uk, RTEST(v));
|
|
110
|
+
|
|
111
111
|
v = rb_hash_aref(options, ID2SYM(rb_intern("allow_unknown_ext")));
|
|
112
112
|
msgpack_unpacker_set_allow_unknown_ext(uk, RTEST(v));
|
|
113
113
|
}
|
|
@@ -121,6 +121,12 @@ static VALUE Unpacker_symbolized_keys_p(VALUE self)
|
|
|
121
121
|
return uk->symbolize_keys ? Qtrue : Qfalse;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
static VALUE Unpacker_freeze_p(VALUE self)
|
|
125
|
+
{
|
|
126
|
+
UNPACKER(self, uk);
|
|
127
|
+
return uk->freeze ? Qtrue : Qfalse;
|
|
128
|
+
}
|
|
129
|
+
|
|
124
130
|
static VALUE Unpacker_allow_unknown_ext_p(VALUE self)
|
|
125
131
|
{
|
|
126
132
|
UNPACKER(self, uk);
|
|
@@ -256,6 +262,17 @@ static VALUE Unpacker_feed(VALUE self, VALUE data)
|
|
|
256
262
|
return self;
|
|
257
263
|
}
|
|
258
264
|
|
|
265
|
+
static VALUE Unpacker_feed_reference(VALUE self, VALUE data)
|
|
266
|
+
{
|
|
267
|
+
UNPACKER(self, uk);
|
|
268
|
+
|
|
269
|
+
StringValue(data);
|
|
270
|
+
|
|
271
|
+
msgpack_buffer_append_string_reference(UNPACKER_BUFFER_(uk), data);
|
|
272
|
+
|
|
273
|
+
return self;
|
|
274
|
+
}
|
|
275
|
+
|
|
259
276
|
static VALUE Unpacker_each_impl(VALUE self)
|
|
260
277
|
{
|
|
261
278
|
UNPACKER(self, uk);
|
|
@@ -312,8 +329,7 @@ static VALUE Unpacker_feed_each(VALUE self, VALUE data)
|
|
|
312
329
|
}
|
|
313
330
|
#endif
|
|
314
331
|
|
|
315
|
-
|
|
316
|
-
Unpacker_feed(self, data);
|
|
332
|
+
Unpacker_feed_reference(self, data);
|
|
317
333
|
return Unpacker_each(self);
|
|
318
334
|
}
|
|
319
335
|
|
|
@@ -353,12 +369,7 @@ static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
|
|
|
353
369
|
case 1:
|
|
354
370
|
/* register_type(0x7f) {|data| block... } */
|
|
355
371
|
rb_need_block();
|
|
356
|
-
#ifdef HAVE_RB_BLOCK_LAMBDA
|
|
357
372
|
proc = rb_block_lambda();
|
|
358
|
-
#else
|
|
359
|
-
/* MRI 1.8 */
|
|
360
|
-
proc = rb_block_proc();
|
|
361
|
-
#endif
|
|
362
373
|
arg = proc;
|
|
363
374
|
ext_module = Qnil;
|
|
364
375
|
break;
|
|
@@ -386,9 +397,6 @@ static VALUE Unpacker_full_unpack(VALUE self)
|
|
|
386
397
|
{
|
|
387
398
|
UNPACKER(self, uk);
|
|
388
399
|
|
|
389
|
-
/* prefer reference than copying; see MessagePack_Unpacker_module_init */
|
|
390
|
-
msgpack_buffer_set_write_reference_threshold(UNPACKER_BUFFER_(uk), 0);
|
|
391
|
-
|
|
392
400
|
int r = msgpack_unpacker_read(uk, 0);
|
|
393
401
|
if(r < 0) {
|
|
394
402
|
raise_unpacker_error(r);
|
|
@@ -434,6 +442,7 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
|
|
|
434
442
|
|
|
435
443
|
rb_define_method(cMessagePack_Unpacker, "initialize", MessagePack_Unpacker_initialize, -1);
|
|
436
444
|
rb_define_method(cMessagePack_Unpacker, "symbolize_keys?", Unpacker_symbolized_keys_p, 0);
|
|
445
|
+
rb_define_method(cMessagePack_Unpacker, "freeze?", Unpacker_freeze_p, 0);
|
|
437
446
|
rb_define_method(cMessagePack_Unpacker, "allow_unknown_ext?", Unpacker_allow_unknown_ext_p, 0);
|
|
438
447
|
rb_define_method(cMessagePack_Unpacker, "buffer", Unpacker_buffer, 0);
|
|
439
448
|
rb_define_method(cMessagePack_Unpacker, "read", Unpacker_read, 0);
|
|
@@ -444,6 +453,7 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
|
|
|
444
453
|
rb_define_method(cMessagePack_Unpacker, "read_map_header", Unpacker_read_map_header, 0);
|
|
445
454
|
//rb_define_method(cMessagePack_Unpacker, "peek_next_type", Unpacker_peek_next_type, 0); // TODO
|
|
446
455
|
rb_define_method(cMessagePack_Unpacker, "feed", Unpacker_feed, 1);
|
|
456
|
+
rb_define_method(cMessagePack_Unpacker, "feed_reference", Unpacker_feed_reference, 1);
|
|
447
457
|
rb_define_method(cMessagePack_Unpacker, "each", Unpacker_each, 0);
|
|
448
458
|
rb_define_method(cMessagePack_Unpacker, "feed_each", Unpacker_feed_each, 1);
|
|
449
459
|
rb_define_method(cMessagePack_Unpacker, "reset", Unpacker_reset, 0);
|
data/lib/msgpack/symbol.rb
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
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
|
+
data.to_sym
|
|
8
18
|
end
|
|
9
|
-
end
|
|
19
|
+
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.4.4"
|
|
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
|
data/lib/msgpack.rb
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
require "msgpack/version"
|
|
2
2
|
|
|
3
3
|
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" # This is same with `/java/ =~ RUBY_VERSION`
|
|
4
|
-
require "java"
|
|
5
4
|
require "msgpack/msgpack.jar"
|
|
6
|
-
org.msgpack.jruby.MessagePackLibrary
|
|
5
|
+
JRuby::Util.load_ext("org.msgpack.jruby.MessagePackLibrary")
|
|
7
6
|
else
|
|
8
|
-
|
|
9
|
-
require "msgpack/#{RUBY_VERSION[/\d+.\d+/]}/msgpack"
|
|
10
|
-
rescue LoadError
|
|
11
|
-
require "msgpack/msgpack"
|
|
12
|
-
end
|
|
7
|
+
require "msgpack/msgpack"
|
|
13
8
|
end
|
|
14
9
|
|
|
15
10
|
require "msgpack/packer"
|
|
@@ -17,6 +12,8 @@ require "msgpack/unpacker"
|
|
|
17
12
|
require "msgpack/factory"
|
|
18
13
|
require "msgpack/symbol"
|
|
19
14
|
require "msgpack/core_ext"
|
|
15
|
+
require "msgpack/timestamp"
|
|
16
|
+
require "msgpack/time"
|
|
20
17
|
|
|
21
18
|
module MessagePack
|
|
22
19
|
DefaultFactory = MessagePack::Factory.new
|
|
@@ -27,7 +24,7 @@ module MessagePack
|
|
|
27
24
|
|
|
28
25
|
if src.is_a? String
|
|
29
26
|
unpacker = DefaultFactory.unpacker param || DEFAULT_EMPTY_PARAMS
|
|
30
|
-
unpacker.
|
|
27
|
+
unpacker.feed_reference src
|
|
31
28
|
else
|
|
32
29
|
unpacker = DefaultFactory.unpacker src, param || DEFAULT_EMPTY_PARAMS
|
|
33
30
|
end
|
data/msgpack.gemspec
CHANGED
|
@@ -10,7 +10,6 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.email = ["frsyuki@gmail.com", "theo@iconara.net", "tagomoris@gmail.com"]
|
|
11
11
|
s.license = "Apache 2.0"
|
|
12
12
|
s.homepage = "http://msgpack.org/"
|
|
13
|
-
s.rubyforge_project = "msgpack"
|
|
14
13
|
s.require_paths = ["lib"]
|
|
15
14
|
if /java/ =~ RUBY_PLATFORM
|
|
16
15
|
s.files = Dir['lib/**/*.rb', 'lib/**/*.jar']
|
|
@@ -19,15 +18,12 @@ Gem::Specification.new do |s|
|
|
|
19
18
|
s.files = `git ls-files`.split("\n")
|
|
20
19
|
s.extensions = ["ext/msgpack/extconf.rb"]
|
|
21
20
|
end
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
s.required_ruby_version = ">= 2.4"
|
|
23
23
|
|
|
24
24
|
s.add_development_dependency 'bundler'
|
|
25
25
|
s.add_development_dependency 'rake'
|
|
26
|
-
s.add_development_dependency 'rake-compiler', ['
|
|
27
|
-
if /java/ !~ RUBY_PLATFORM
|
|
28
|
-
# NOTE: rake-compiler-dock SHOULD be updated for new Ruby versions
|
|
29
|
-
s.add_development_dependency 'rake-compiler-dock', ['~> 0.7.0']
|
|
30
|
-
end
|
|
26
|
+
s.add_development_dependency 'rake-compiler', ['>= 1.1.9']
|
|
31
27
|
s.add_development_dependency 'rspec', ['~> 3.3']
|
|
32
28
|
s.add_development_dependency 'yard'
|
|
33
29
|
s.add_development_dependency 'json'
|
data/spec/factory_spec.rb
CHANGED
|
@@ -280,6 +280,23 @@ describe MessagePack::Factory do
|
|
|
280
280
|
unpacker.feed(packed_symbol).unpack
|
|
281
281
|
end
|
|
282
282
|
|
|
283
|
+
context 'using the optimized symbol unpacker' do
|
|
284
|
+
before do
|
|
285
|
+
skip if IS_JRUBY # JRuby implementation doesn't support the optimized symbols unpacker for now
|
|
286
|
+
subject.register_type(
|
|
287
|
+
0x00,
|
|
288
|
+
::Symbol,
|
|
289
|
+
packer: :to_msgpack_ext,
|
|
290
|
+
unpacker: :from_msgpack_ext,
|
|
291
|
+
optimized_symbols_parsing: true,
|
|
292
|
+
)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
it 'lets symbols survive a roundtrip' do
|
|
296
|
+
expect(symbol_after_roundtrip).to be :symbol
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
283
300
|
context 'if no ext type is registered for symbols' do
|
|
284
301
|
it 'converts symbols to string' do
|
|
285
302
|
expect(symbol_after_roundtrip).to eq 'symbol'
|
data/spec/msgpack_spec.rb
CHANGED
|
@@ -115,7 +115,7 @@ describe MessagePack do
|
|
|
115
115
|
expect { MessagePack.pack(self) }.to raise_error(NoMethodError, /^undefined method `to_msgpack'/)
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
it '
|
|
118
|
+
it 'raises an error on #unpack with garbage' do
|
|
119
119
|
skip "but nothing was raised. why?"
|
|
120
120
|
expect { MessagePack.unpack('asdka;sd') }.to raise_error(MessagePack::UnpackError)
|
|
121
121
|
end
|
data/spec/packer_spec.rb
CHANGED
|
@@ -488,6 +488,24 @@ describe MessagePack::Packer do
|
|
|
488
488
|
it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" }
|
|
489
489
|
end
|
|
490
490
|
|
|
491
|
+
shared_examples_for 'extension subclasses core type' do |klass|
|
|
492
|
+
before { stub_const('Value', Class.new(klass)) }
|
|
493
|
+
let(:object) { Value.new }
|
|
494
|
+
subject { packer.pack(object).to_s }
|
|
495
|
+
|
|
496
|
+
it "defaults to #{klass.name} packer if no extension is present" do
|
|
497
|
+
expect(subject).to eq(MessagePack.dump(klass.new))
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
it "uses core type extension for #{klass.name}" do
|
|
501
|
+
packer.register_type(0x01, Value, ->(_) { 'value_msgpacked' })
|
|
502
|
+
expect(subject).to eq("\xC7\x0F\x01value_msgpacked")
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
it_behaves_like 'extension subclasses core type', Hash
|
|
506
|
+
it_behaves_like 'extension subclasses core type', Array
|
|
507
|
+
it_behaves_like 'extension subclasses core type', String
|
|
508
|
+
|
|
491
509
|
context 'when registering a type for symbols' do
|
|
492
510
|
before { packer.register_type(0x00, ::Symbol, :to_msgpack_ext) }
|
|
493
511
|
|
data/spec/spec_helper.rb
CHANGED
|
@@ -15,10 +15,37 @@ end
|
|
|
15
15
|
|
|
16
16
|
require 'msgpack'
|
|
17
17
|
|
|
18
|
+
if GC.respond_to?(:verify_compaction_references)
|
|
19
|
+
# This method was added in Ruby 3.0.0. Calling it this way asks the GC to
|
|
20
|
+
# move objects around, helping to find object movement bugs.
|
|
21
|
+
GC.verify_compaction_references(double_heap: true, toward: :empty)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if GC.respond_to?(:auto_compact=)
|
|
25
|
+
GC.auto_compact = true
|
|
26
|
+
end
|
|
27
|
+
|
|
18
28
|
def java?
|
|
19
29
|
/java/ =~ RUBY_PLATFORM
|
|
20
30
|
end
|
|
21
31
|
|
|
32
|
+
# checking if Hash#[]= (rb_hash_aset) dedupes string keys
|
|
33
|
+
def automatic_string_keys_deduplication?
|
|
34
|
+
h = {}
|
|
35
|
+
x = {}
|
|
36
|
+
r = rand.to_s
|
|
37
|
+
h[%W(#{r}).join('')] = :foo
|
|
38
|
+
x[%W(#{r}).join('')] = :foo
|
|
39
|
+
|
|
40
|
+
x.keys[0].equal?(h.keys[0])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def string_deduplication?
|
|
44
|
+
r1 = rand.to_s
|
|
45
|
+
r2 = r1.dup
|
|
46
|
+
(-r1).equal?(-r2)
|
|
47
|
+
end
|
|
48
|
+
|
|
22
49
|
if java?
|
|
23
50
|
RSpec.configure do |c|
|
|
24
51
|
c.treat_symbols_as_metadata_keys_with_true_values = true
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
IS_JRUBY = Kernel.const_defined?(:JRUBY_VERSION)
|
|
6
|
+
|
|
7
|
+
describe MessagePack::Timestamp do
|
|
8
|
+
describe 'malformed format' do
|
|
9
|
+
it do
|
|
10
|
+
expect do
|
|
11
|
+
MessagePack::Timestamp.from_msgpack_ext([0xd4, 0x00].pack("C*"))
|
|
12
|
+
end.to raise_error(MessagePack::MalformedFormatError)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe 'register_type with Time' do
|
|
17
|
+
let(:factory) do
|
|
18
|
+
factory = MessagePack::Factory.new
|
|
19
|
+
factory.register_type(
|
|
20
|
+
MessagePack::Timestamp::TYPE,
|
|
21
|
+
Time,
|
|
22
|
+
packer: MessagePack::Time::Packer,
|
|
23
|
+
unpacker: MessagePack::Time::Unpacker
|
|
24
|
+
)
|
|
25
|
+
factory
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
let(:time) { Time.local(2019, 6, 17, 1, 2, 3, 123_456_789 / 1000.0) }
|
|
29
|
+
it 'serializes and deserializes Time' do
|
|
30
|
+
prefix_fixext8_with_type_id = [0xd7, -1].pack("c*")
|
|
31
|
+
|
|
32
|
+
packed = factory.pack(time)
|
|
33
|
+
expect(packed).to start_with(prefix_fixext8_with_type_id)
|
|
34
|
+
expect(packed.size).to eq(10)
|
|
35
|
+
unpacked = factory.unpack(packed)
|
|
36
|
+
expect(unpacked.to_i).to eq(time.to_i)
|
|
37
|
+
expect(unpacked.to_f).to eq(time.to_f)
|
|
38
|
+
# expect(unpacked).to eq(time) # we can't do it because of nsec (rational vs float?)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
let(:time_without_nsec) { Time.local(2019, 6, 17, 1, 2, 3, 0) }
|
|
42
|
+
it 'serializes time without nanosec as fixext4' do
|
|
43
|
+
prefix_fixext4_with_type_id = [0xd6, -1].pack("c*")
|
|
44
|
+
|
|
45
|
+
packed = factory.pack(time_without_nsec)
|
|
46
|
+
expect(packed).to start_with(prefix_fixext4_with_type_id)
|
|
47
|
+
expect(packed.size).to eq(6)
|
|
48
|
+
unpacked = factory.unpack(packed)
|
|
49
|
+
expect(unpacked).to eq(time_without_nsec)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
let(:time_after_2514) { Time.at(1 << 34) } # the max num of 34bit int means 2514-05-30 01:53:04 UTC
|
|
53
|
+
it 'serializes time after 2038 as ext8' do
|
|
54
|
+
prefix_ext8_with_12bytes_payload_and_type_id = [0xc7, 12, -1].pack("c*")
|
|
55
|
+
|
|
56
|
+
expect(time_after_2514.to_i).to be > 0xffffffff
|
|
57
|
+
packed = factory.pack(time_after_2514)
|
|
58
|
+
expect(packed).to start_with(prefix_ext8_with_12bytes_payload_and_type_id)
|
|
59
|
+
expect(packed.size).to eq(15)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'runs correctly (regression)' do
|
|
63
|
+
expect(factory.unpack(factory.pack(Time.utc(2200)))).to eq(Time.utc(2200))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
let(:time32_max) { Time.new(2106, 2, 7, 6, 28, 15, "+00:00") }
|
|
67
|
+
it 'is serialized into timestamp32' do
|
|
68
|
+
expect(factory.pack(time32_max).size).to be 6
|
|
69
|
+
expect(factory.unpack(factory.pack(time32_max)).utc).to eq(time32_max)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
let(:time64_min) { Time.new(2106, 2, 7, 6, 28, 16, "+00:00") }
|
|
73
|
+
it 'is serialized into timestamp64' do
|
|
74
|
+
expect(factory.pack(time64_min).size).to be 10
|
|
75
|
+
expect(factory.unpack(factory.pack(time64_min)).utc).to eq(time64_min)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
let(:time64_max) { Time.at(Time.new(2514, 5, 30, 1, 53, 3, "+00:00").to_i, 999999999 / 1000.0r).utc } # TODO: use Time.at(sec, nsec, :nsec) when removing Ruby 2.4 from the list
|
|
79
|
+
it 'is serialized into timestamp64' do
|
|
80
|
+
expect(factory.pack(time64_max).size).to be 10
|
|
81
|
+
expect(factory.unpack(factory.pack(time64_max)).utc).to eq(time64_max)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
let(:time96_positive_min) { Time.new(2514, 5, 30, 1, 53, 4, "+00:00") }
|
|
85
|
+
it 'is serialized into timestamp96' do
|
|
86
|
+
expect(factory.pack(time96_positive_min).size).to be 15
|
|
87
|
+
expect(factory.unpack(factory.pack(time96_positive_min)).utc).to eq(time96_positive_min)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
let(:time96_min) { Time.at(-2**63).utc }
|
|
91
|
+
it 'is serialized into timestamp96' do
|
|
92
|
+
skip if IS_JRUBY # JRuby cannot handle numerics larger than long
|
|
93
|
+
expect(factory.pack(time96_min).size).to be 15
|
|
94
|
+
expect(factory.unpack(factory.pack(time96_min)).utc).to eq(time96_min)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
let(:time96_max) { Time.at(2**63 - 1).utc }
|
|
98
|
+
it 'is serialized into timestamp96' do
|
|
99
|
+
skip if IS_JRUBY # JRuby cannot handle numerics larger than long
|
|
100
|
+
expect(factory.pack(time96_max).size).to be 15
|
|
101
|
+
expect(factory.unpack(factory.pack(time96_max)).utc).to eq(time96_max)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe 'register_type with MessagePack::Timestamp' do
|
|
106
|
+
let(:factory) do
|
|
107
|
+
factory = MessagePack::Factory.new
|
|
108
|
+
factory.register_type(MessagePack::Timestamp::TYPE, MessagePack::Timestamp)
|
|
109
|
+
factory
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
let(:timestamp) { MessagePack::Timestamp.new(Time.now.tv_sec, 123_456_789) }
|
|
113
|
+
it 'serializes and deserializes MessagePack::Timestamp' do
|
|
114
|
+
packed = factory.pack(timestamp)
|
|
115
|
+
unpacked = factory.unpack(packed)
|
|
116
|
+
expect(unpacked).to eq(timestamp)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe 'timestamp32' do
|
|
121
|
+
it 'handles [1, 0]' do
|
|
122
|
+
t = MessagePack::Timestamp.new(1, 0)
|
|
123
|
+
|
|
124
|
+
payload = t.to_msgpack_ext
|
|
125
|
+
unpacked = MessagePack::Timestamp.from_msgpack_ext(payload)
|
|
126
|
+
|
|
127
|
+
expect(unpacked).to eq(t)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe 'timestamp64' do
|
|
132
|
+
it 'handles [1, 1]' do
|
|
133
|
+
t = MessagePack::Timestamp.new(1, 1)
|
|
134
|
+
|
|
135
|
+
payload = t.to_msgpack_ext
|
|
136
|
+
unpacked = MessagePack::Timestamp.from_msgpack_ext(payload)
|
|
137
|
+
|
|
138
|
+
expect(unpacked).to eq(t)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe 'timestamp96' do
|
|
143
|
+
it 'handles [-1, 0]' do
|
|
144
|
+
t = MessagePack::Timestamp.new(-1, 0)
|
|
145
|
+
|
|
146
|
+
payload = t.to_msgpack_ext
|
|
147
|
+
unpacked = MessagePack::Timestamp.from_msgpack_ext(payload)
|
|
148
|
+
|
|
149
|
+
expect(unpacked).to eq(t)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'handles [-1, 999_999_999]' do
|
|
153
|
+
t = MessagePack::Timestamp.new(-1, 999_999_999)
|
|
154
|
+
|
|
155
|
+
payload = t.to_msgpack_ext
|
|
156
|
+
unpacked = MessagePack::Timestamp.from_msgpack_ext(payload)
|
|
157
|
+
|
|
158
|
+
expect(unpacked).to eq(t)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|