msgpack 0.7.4 → 1.3.3

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 (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