msgpack 0.7.4 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -1
  3. data/.rubocop.yml +3 -0
  4. data/.travis.yml +27 -14
  5. data/ChangeLog +89 -1
  6. data/Gemfile +6 -1
  7. data/README.rdoc +55 -1
  8. data/Rakefile +5 -1
  9. data/bench/pack_symbols.rb +28 -0
  10. data/bench/run_symbols.sh +26 -0
  11. data/doclib/msgpack.rb +2 -2
  12. data/doclib/msgpack/core_ext.rb +20 -20
  13. data/doclib/msgpack/factory.rb +33 -0
  14. data/doclib/msgpack/packer.rb +20 -0
  15. data/doclib/msgpack/time.rb +22 -0
  16. data/doclib/msgpack/timestamp.rb +44 -0
  17. data/ext/java/org/msgpack/jruby/Buffer.java +4 -0
  18. data/ext/java/org/msgpack/jruby/Encoder.java +48 -18
  19. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +67 -38
  20. data/ext/java/org/msgpack/jruby/Factory.java +20 -8
  21. data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +0 -92
  22. data/ext/java/org/msgpack/jruby/Packer.java +114 -11
  23. data/ext/java/org/msgpack/jruby/Unpacker.java +15 -8
  24. data/ext/msgpack/buffer.h +14 -0
  25. data/ext/msgpack/buffer_class.c +1 -1
  26. data/ext/msgpack/compat.h +10 -0
  27. data/ext/msgpack/factory_class.c +24 -17
  28. data/ext/msgpack/factory_class.h +0 -2
  29. data/ext/msgpack/packer.c +5 -4
  30. data/ext/msgpack/packer.h +13 -1
  31. data/ext/msgpack/packer_class.c +130 -43
  32. data/ext/msgpack/packer_class.h +0 -2
  33. data/ext/msgpack/packer_ext_registry.c +2 -2
  34. data/ext/msgpack/packer_ext_registry.h +64 -25
  35. data/ext/msgpack/rbinit.c +0 -2
  36. data/ext/msgpack/unpacker.c +3 -3
  37. data/ext/msgpack/unpacker_class.c +25 -56
  38. data/ext/msgpack/unpacker_class.h +0 -2
  39. data/ext/msgpack/unpacker_ext_registry.c +2 -2
  40. data/ext/msgpack/unpacker_ext_registry.h +3 -3
  41. data/lib/msgpack.rb +36 -0
  42. data/lib/msgpack/core_ext.rb +139 -0
  43. data/lib/msgpack/factory.rb +21 -0
  44. data/lib/msgpack/symbol.rb +9 -0
  45. data/lib/msgpack/time.rb +29 -0
  46. data/lib/msgpack/timestamp.rb +76 -0
  47. data/lib/msgpack/version.rb +8 -1
  48. data/msgpack.gemspec +6 -7
  49. data/spec/cruby/buffer_spec.rb +6 -1
  50. data/spec/factory_spec.rb +134 -0
  51. data/spec/msgpack_spec.rb +52 -0
  52. data/spec/packer_spec.rb +200 -0
  53. data/spec/timestamp_spec.rb +121 -0
  54. data/spec/unpacker_spec.rb +29 -0
  55. metadata +29 -23
  56. data/ext/msgpack/core_ext.c +0 -144
  57. data/ext/msgpack/core_ext.h +0 -26
@@ -0,0 +1,139 @@
1
+ module MessagePack
2
+ module CoreExt
3
+ def to_msgpack(packer_or_io = nil)
4
+ if packer_or_io
5
+ if packer_or_io.is_a?(MessagePack::Packer)
6
+ to_msgpack_with_packer packer_or_io
7
+ else
8
+ MessagePack.pack(self, packer_or_io)
9
+ end
10
+ else
11
+ MessagePack.pack(self)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ class NilClass
18
+ include MessagePack::CoreExt
19
+
20
+ private
21
+ def to_msgpack_with_packer(packer)
22
+ packer.write_nil
23
+ packer
24
+ end
25
+ end
26
+
27
+ class TrueClass
28
+ include MessagePack::CoreExt
29
+
30
+ private
31
+ def to_msgpack_with_packer(packer)
32
+ packer.write_true
33
+ packer
34
+ end
35
+ end
36
+
37
+ class FalseClass
38
+ include MessagePack::CoreExt
39
+
40
+ private
41
+ def to_msgpack_with_packer(packer)
42
+ packer.write_false
43
+ packer
44
+ end
45
+ end
46
+
47
+ class Float
48
+ include MessagePack::CoreExt
49
+
50
+ private
51
+ def to_msgpack_with_packer(packer)
52
+ packer.write_float self
53
+ packer
54
+ end
55
+ end
56
+
57
+ class String
58
+ include MessagePack::CoreExt
59
+
60
+ private
61
+ def to_msgpack_with_packer(packer)
62
+ packer.write_string self
63
+ packer
64
+ end
65
+ end
66
+
67
+ class Array
68
+ include MessagePack::CoreExt
69
+
70
+ private
71
+ def to_msgpack_with_packer(packer)
72
+ packer.write_array self
73
+ packer
74
+ end
75
+ end
76
+
77
+ class Hash
78
+ include MessagePack::CoreExt
79
+
80
+ private
81
+ def to_msgpack_with_packer(packer)
82
+ packer.write_hash self
83
+ packer
84
+ end
85
+ end
86
+
87
+ class Symbol
88
+ include MessagePack::CoreExt
89
+
90
+ private
91
+ def to_msgpack_with_packer(packer)
92
+ packer.write_symbol self
93
+ packer
94
+ end
95
+ end
96
+
97
+ if 1.class.name == "Integer"
98
+ class Integer
99
+ include MessagePack::CoreExt
100
+
101
+ private
102
+ def to_msgpack_with_packer(packer)
103
+ packer.write_int self
104
+ packer
105
+ end
106
+ end
107
+ else
108
+ class Fixnum
109
+ include MessagePack::CoreExt
110
+
111
+ private
112
+ def to_msgpack_with_packer(packer)
113
+ packer.write_int self
114
+ packer
115
+ end
116
+ end
117
+
118
+ class Bignum
119
+ include MessagePack::CoreExt
120
+
121
+ private
122
+ def to_msgpack_with_packer(packer)
123
+ packer.write_int self
124
+ packer
125
+ end
126
+ end
127
+ end
128
+
129
+ module MessagePack
130
+ class ExtensionValue
131
+ include CoreExt
132
+
133
+ private
134
+ def to_msgpack_with_packer(packer)
135
+ packer.write_extension self
136
+ packer
137
+ end
138
+ end
139
+ end
@@ -56,5 +56,26 @@ module MessagePack
56
56
  raise ArgumentError, "class or type id"
57
57
  end
58
58
  end
59
+
60
+ def load(src, param = nil)
61
+ unpacker = nil
62
+
63
+ if src.is_a? String
64
+ unpacker = unpacker(param)
65
+ unpacker.feed(src)
66
+ else
67
+ unpacker = unpacker(src, param)
68
+ end
69
+
70
+ unpacker.full_unpack
71
+ end
72
+ alias :unpack :load
73
+
74
+ def dump(v, *rest)
75
+ packer = packer(*rest)
76
+ packer.write(v)
77
+ packer.full_pack
78
+ end
79
+ alias :pack :dump
59
80
  end
60
81
  end
@@ -0,0 +1,9 @@
1
+ class Symbol
2
+ def to_msgpack_ext
3
+ [to_s].pack('A*')
4
+ end
5
+
6
+ def self.from_msgpack_ext(data)
7
+ data.unpack('A*').first.to_sym
8
+ end
9
+ 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.0)
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,3 +1,10 @@
1
1
  module MessagePack
2
- VERSION = "0.7.4"
2
+ VERSION = "1.3.3"
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
+ # https://github.com/rake-compiler/rake-compiler-dock/blob/master/History.md
8
+ # * update RUBY_CC_VERSION in Rakefile
9
+ # * check Ruby dependency of released mswin gem details
3
10
  end
data/msgpack.gemspec CHANGED
@@ -10,8 +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
- s.has_rdoc = false
15
13
  s.require_paths = ["lib"]
16
14
  if /java/ =~ RUBY_PLATFORM
17
15
  s.files = Dir['lib/**/*.rb', 'lib/**/*.jar']
@@ -22,13 +20,14 @@ Gem::Specification.new do |s|
22
20
  end
23
21
  s.test_files = `git ls-files -- {test,spec}/*`.split("\n")
24
22
 
25
- s.add_development_dependency 'bundler', ['~> 1.0']
26
- s.add_development_dependency 'rake', ['~> 0.9.2']
27
- s.add_development_dependency 'rake-compiler', ['~> 0.9.4']
23
+ s.add_development_dependency 'bundler'
24
+ s.add_development_dependency 'rake'
25
+ s.add_development_dependency 'rake-compiler', ['~> 1.0']
28
26
  if /java/ !~ RUBY_PLATFORM
29
- s.add_development_dependency 'rake-compiler-dock', ['~> 0.5.0']
27
+ # NOTE: rake-compiler-dock SHOULD be updated for new Ruby versions
28
+ s.add_development_dependency 'rake-compiler-dock', ['~> 1.0']
30
29
  end
31
30
  s.add_development_dependency 'rspec', ['~> 3.3']
32
- s.add_development_dependency 'yard', ['~> 0.8.2']
31
+ s.add_development_dependency 'yard'
33
32
  s.add_development_dependency 'json'
34
33
  end
@@ -1,6 +1,11 @@
1
1
  require 'spec_helper'
2
2
  require 'random_compat'
3
3
 
4
+ require 'stringio'
5
+ if defined?(Encoding)
6
+ Encoding.default_external = 'ASCII-8BIT'
7
+ end
8
+
4
9
  describe Buffer do
5
10
  STATIC_EXAMPLES = {}
6
11
  STATIC_EXAMPLES[:empty01] = ''
@@ -45,7 +50,7 @@ describe Buffer do
45
50
  b.read(n)
46
51
  s.slice!(0, n)
47
52
  end
48
- key = :"random#{"%02d"%i}"
53
+ key = :"random#{"%02d" % i}"
49
54
  cases[key] = b
50
55
  examples[key] = s
51
56
  end
data/spec/factory_spec.rb CHANGED
@@ -44,6 +44,32 @@ describe MessagePack::Factory do
44
44
  end
45
45
  end
46
46
 
47
+ describe '#dump and #load' do
48
+ it 'can be used like a standard coder' do
49
+ subject.register_type(0x00, Symbol)
50
+ expect(subject.load(subject.dump(:symbol))).to be == :symbol
51
+ end
52
+
53
+ it 'is alias as pack and unpack' do
54
+ subject.register_type(0x00, Symbol)
55
+ expect(subject.unpack(subject.pack(:symbol))).to be == :symbol
56
+ end
57
+
58
+ it 'accept options' do
59
+ hash = subject.unpack(MessagePack.pack('k' => 'v'), symbolize_keys: true)
60
+ expect(hash).to be == { k: 'v' }
61
+ end
62
+ end
63
+
64
+ describe '#freeze' do
65
+ it 'can freeze factory instance to deny new registrations anymore' do
66
+ subject.register_type(0x00, Symbol)
67
+ subject.freeze
68
+ expect(subject.frozen?).to be_truthy
69
+ expect{ subject.register_type(0x01, Array) }.to raise_error(RuntimeError, "can't modify frozen Factory")
70
+ end
71
+ end
72
+
47
73
  class MyType
48
74
  def initialize(a, b)
49
75
  @a = a
@@ -208,6 +234,114 @@ describe MessagePack::Factory do
208
234
  my.a.should == 1
209
235
  my.b.should == 2
210
236
  end
237
+
238
+ describe "registering an ext type for a module" do
239
+ before do
240
+ mod = Module.new do
241
+ def self.from_msgpack_ext(data)
242
+ "unpacked #{data}"
243
+ end
244
+
245
+ def to_msgpack_ext
246
+ 'value_msgpacked'
247
+ end
248
+ end
249
+ stub_const('Mod', mod)
250
+ end
251
+ let(:factory) { described_class.new }
252
+ before { factory.register_type(0x01, Mod) }
253
+
254
+ describe "packing an object whose class included the module" do
255
+ subject { factory.packer.pack(value).to_s }
256
+ before { stub_const('Value', Class.new{ include Mod }) }
257
+ let(:value) { Value.new }
258
+ it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" }
259
+ end
260
+
261
+ describe "packing an object which has been extended by the module" do
262
+ subject { factory.packer.pack(object).to_s }
263
+ let(:object) { Object.new.extend Mod }
264
+ it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" }
265
+ end
266
+
267
+ describe "unpacking with the module" do
268
+ subject { factory.unpacker.feed("\xC7\x06\x01module").unpack }
269
+ it { is_expected.to eq "unpacked module" }
270
+ end
271
+ end
272
+ end
273
+
274
+ describe 'the special treatment of symbols with ext type' do
275
+ let(:packer) { subject.packer }
276
+ let(:unpacker) { subject.unpacker }
277
+
278
+ def symbol_after_roundtrip
279
+ packed_symbol = packer.pack(:symbol).to_s
280
+ unpacker.feed(packed_symbol).unpack
281
+ end
282
+
283
+ context 'if no ext type is registered for symbols' do
284
+ it 'converts symbols to string' do
285
+ expect(symbol_after_roundtrip).to eq 'symbol'
286
+ end
287
+ end
288
+
289
+ context 'if an ext type is registered for symbols' do
290
+ context 'if using the default serializer' do
291
+ before { subject.register_type(0x00, ::Symbol) }
292
+
293
+ it 'lets symbols survive a roundtrip' do
294
+ expect(symbol_after_roundtrip).to be :symbol
295
+ end
296
+ end
297
+
298
+ context 'if using a custom serializer' do
299
+ before do
300
+ class Symbol
301
+ alias_method :to_msgpack_ext_orig, :to_msgpack_ext
302
+ def to_msgpack_ext
303
+ self.to_s.codepoints.to_a.pack('n*')
304
+ end
305
+ end
306
+
307
+ class << Symbol
308
+ alias_method :from_msgpack_ext_orig, :from_msgpack_ext
309
+ def from_msgpack_ext(data)
310
+ data.unpack('n*').map(&:chr).join.to_sym
311
+ end
312
+ end
313
+ end
314
+
315
+ before { subject.register_type(0x00, ::Symbol) }
316
+
317
+ it 'lets symbols survive a roundtrip' do
318
+ expect(symbol_after_roundtrip).to be :symbol
319
+ end
320
+
321
+ after do
322
+ class Symbol
323
+ alias_method :to_msgpack_ext, :to_msgpack_ext_orig
324
+ end
325
+
326
+ class << Symbol
327
+ alias_method :from_msgpack_ext, :from_msgpack_ext_orig
328
+ end
329
+ end
330
+ end
331
+ end
332
+ end
333
+
334
+ describe 'under stressful GC' do
335
+ it 'works well' do
336
+ begin
337
+ GC.stress = true
338
+
339
+ f = MessagePack::Factory.new
340
+ f.register_type(0x0a, Symbol)
341
+ ensure
342
+ GC.stress = false
343
+ end
344
+ end
211
345
  end
212
346
 
213
347
  describe 'DefaultFactory' do