msgpack 1.4.0.pre1 → 1.4.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dce37069bf08ffa0b29a76363cee45e3d8e19188236d673dc1c9b4172727738c
4
- data.tar.gz: 3c30d3ac0b3a3b4f5432e958935370f2e55d16ce516bf6a91eb12382aad38d8b
3
+ metadata.gz: 451ed743fe37bd3726f897f4daae9e7fd9b2cb065a34cf438ca786350060e0ec
4
+ data.tar.gz: 87335c4b1d35f9ac88af648963b1fe60caa72059ec7e6c1b6b507027da9118d8
5
5
  SHA512:
6
- metadata.gz: 53d062f57dcd7324a04224c16dedbe7aa0188515d595f5a38ca543e0b956db8bbd3906a59cf3faceb5c0fb3b23d10be47bb34d19146c61923818f8f856c0a726
7
- data.tar.gz: 408bcb8f9cde8c88ac6a0620a8a64c746e34723b582aa160b53687f7b5206a9cdcf97efb97eafcf6357cee6412ae3d0346a952e97b979f7c4eeffe23150d7ec4
6
+ metadata.gz: eb519049e9d8e4b36682e4b2c2625f10172745ce74ad1cfc8e6d93468b219071ed579bcfd36b7f0e1210eeb177197b435da2a028f46d2c71c73a3bcf2b53dcf8
7
+ data.tar.gz: e8c4765ac836226f5a2ce68a62194f112fc77bcdd9744d39040ff2db5a2c27d876348fb6002110c00b122bccdff2d539223d82ff73ea0bcb4cf1a3d9fb62defe
data/ChangeLog CHANGED
@@ -1,3 +1,17 @@
1
+ 2021-02-01 version 1.4.2:
2
+
3
+ * Add the required Ruby version (>= 2.4) to avoid compilation errors on older Ruby runtimes
4
+ * Drop the support of old Ruby versions explicitly (1.8, 1.9, 2.0, 2.1, 2.2, 2.3)
5
+
6
+ 2021-01-27 version 1.4.1:
7
+
8
+ * Bugfix about the wrong string encoding longer than 256 bytes (#200)
9
+
10
+ 2021-01-27 version 1.4.0:
11
+
12
+ * Introduce the optimization to use frozen/deduped keys for map objects
13
+ * Stop releasing fat gem (pre-built binaries) for mswin32 arch environments
14
+
1
15
  2020-02-05 version 1.3.3:
2
16
 
3
17
  * Hotfix release for Windows environments: 1.3.2 missed including binaries
data/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # MessagePack
2
+
3
+ [MessagePack](http://msgpack.org) is an efficient binary serialization format.
4
+ It lets you exchange data among multiple languages like JSON but it's faster and smaller.
5
+ For example, small integers (like flags or error code) are encoded into a single byte,
6
+ and typical short strings only require an extra byte in addition to the strings themselves.
7
+
8
+ If you ever wished to use JSON for convenience (storing an image with metadata) but could
9
+ not for technical reasons (binary data, size, speed...), MessagePack is a perfect replacement.
10
+
11
+ require 'msgpack'
12
+ msg = [1,2,3].to_msgpack #=> "\x93\x01\x02\x03"
13
+ MessagePack.unpack(msg) #=> [1,2,3]
14
+
15
+ Use RubyGems to install:
16
+
17
+ gem install msgpack
18
+
19
+ or build msgpack-ruby and install:
20
+
21
+ bundle
22
+ rake
23
+ gem install --local pkg/msgpack
24
+
25
+
26
+ ## Use cases
27
+
28
+ * Create REST API returing MessagePack using Rails + [RABL](https://github.com/nesquena/rabl)
29
+ * Store objects efficiently serialized by msgpack on memcached or Redis
30
+ * In fact Redis supports msgpack in [EVAL-scripts](http://redis.io/commands/eval)
31
+ * Upload data in efficient format from mobile devices such as smartphones
32
+ * MessagePack works on iPhone/iPad and Android. See also [Objective-C](https://github.com/msgpack/msgpack-objectivec) and [Java](https://github.com/msgpack/msgpack-java) implementations
33
+ * Design a portable protocol to communicate with embedded devices
34
+ * Check also [Fluentd](http://fluentd.org/) which is a log collector which uses msgpack for the log format (they say it uses JSON but actually it's msgpack, which is compatible with JSON)
35
+ * Exchange objects between software components written in different languages
36
+ * You'll need a flexible but efficient format so that components exchange objects while keeping compatibility
37
+
38
+ ## Portability
39
+
40
+ MessagePack for Ruby should run on x86, ARM, PowerPC, SPARC and other CPU architectures.
41
+
42
+ And it works with MRI (CRuby) and Rubinius.
43
+ Patches to improve portability is highly welcomed.
44
+
45
+
46
+ ## Serializing objects
47
+
48
+ Use `MessagePack.pack` or `to_msgpack`:
49
+
50
+ ```ruby
51
+ require 'msgpack'
52
+ msg = MessagePack.pack(obj) # or
53
+ msg = obj.to_msgpack
54
+ ```
55
+
56
+ ### Streaming serialization
57
+
58
+ Packer provides advanced API to serialize objects in streaming style:
59
+
60
+ ```ruby
61
+ # serialize a 2-element array [e1, e2]
62
+ pk = MessagePack::Packer.new(io)
63
+ pk.write_array_header(2).write(e1).write(e2).flush
64
+ ```
65
+
66
+ See [API reference](http://ruby.msgpack.org/MessagePack/Packer.html) for details.
67
+
68
+ ## Deserializing objects
69
+
70
+ Use `MessagePack.unpack`:
71
+
72
+ ```ruby
73
+ require 'msgpack'
74
+ obj = MessagePack.unpack(msg)
75
+ ```
76
+
77
+ ### Streaming deserialization
78
+
79
+ Unpacker provides advanced API to deserialize objects in streaming style:
80
+
81
+ ```ruby
82
+ # deserialize objects from an IO
83
+ u = MessagePack::Unpacker.new(io)
84
+ u.each do |obj|
85
+ # ...
86
+ end
87
+ ```
88
+
89
+ or event-driven style which works well with EventMachine:
90
+
91
+ ```ruby
92
+ # event-driven deserialization
93
+ def on_read(data)
94
+ @u ||= MessagePack::Unpacker.new
95
+ @u.feed_each(data) {|obj|
96
+ # ...
97
+ }
98
+ end
99
+ ```
100
+
101
+ See [API reference](http://ruby.msgpack.org/MessagePack/Unpacker.html) for details.
102
+
103
+ ## Serializing and deserializing symbols
104
+
105
+ By default, symbols are serialized as strings:
106
+
107
+ ```ruby
108
+ packed = :symbol.to_msgpack # => "\xA6symbol"
109
+ MessagePack.unpack(packed) # => "symbol"
110
+ ```
111
+
112
+ This can be customized by registering an extension type for them:
113
+
114
+ ```ruby
115
+ MessagePack::DefaultFactory.register_type(0x00, Symbol)
116
+
117
+ # symbols now survive round trips
118
+ packed = :symbol.to_msgpack # => "\xc7\x06\x00symbol"
119
+ MessagePack.unpack(packed) # => :symbol
120
+ ```
121
+
122
+ The extension type for symbols is configurable like any other extension type.
123
+ For example, to customize how symbols are packed you can just redefine
124
+ Symbol#to_msgpack_ext. Doing this gives you an option to prevent symbols from
125
+ being serialized altogether by throwing an exception:
126
+
127
+ ```ruby
128
+ class Symbol
129
+ def to_msgpack_ext
130
+ raise "Serialization of symbols prohibited"
131
+ end
132
+ end
133
+
134
+ MessagePack::DefaultFactory.register_type(0x00, Symbol)
135
+
136
+ [1, :symbol, 'string'].to_msgpack # => RuntimeError: Serialization of symbols prohibited
137
+ ```
138
+
139
+ ## Serializing and deserializing Time instances
140
+
141
+ There are the timestamp extension type in MessagePack,
142
+ but it is not registered by default.
143
+
144
+ To map Ruby's Time to MessagePack's timestamp for the default factory:
145
+
146
+ ```ruby
147
+ MessagePack::DefaultFactory.register_type(
148
+ MessagePack::Timestamp::TYPE, # or just -1
149
+ Time,
150
+ packer: MessagePack::Time::Packer,
151
+ unpacker: MessagePack::Time::Unpacker
152
+ )
153
+ ```
154
+
155
+ See [API reference](http://ruby.msgpack.org/) for details.
156
+
157
+ ## Extension Types
158
+
159
+ Packer and Unpacker support [Extension types of MessagePack](https://github.com/msgpack/msgpack/blob/master/spec.md#types-extension-type).
160
+
161
+ ```ruby
162
+ # register how to serialize custom class at first
163
+ pk = MessagePack::Packer.new(io)
164
+ pk.register_type(0x01, MyClass1, :to_msgpack_ext) # equal to pk.register_type(0x01, MyClass)
165
+ pk.register_type(0x02, MyClass2){|obj| obj.how_to_serialize() } # blocks also available
166
+
167
+ # almost same API for unpacker
168
+ uk = MessagePack::Unpacker.new()
169
+ uk.register_type(0x01, MyClass1, :from_msgpack_ext)
170
+ uk.register_type(0x02){|data| MyClass2.create_from_serialized_data(data) }
171
+ ```
172
+
173
+ `MessagePack::Factory` is to create packer and unpacker which have same extension types.
174
+
175
+ ```ruby
176
+ factory = MessagePack::Factory.new
177
+ factory.register_type(0x01, MyClass1) # same with next line
178
+ factory.register_type(0x01, MyClass1, packer: :to_msgpack_ext, unpacker: :from_msgpack_ext)
179
+ pk = factory.packer(options_for_packer)
180
+ uk = factory.unpacker(options_for_unpacker)
181
+ ```
182
+
183
+ For `MessagePack.pack` and `MessagePack.unpack`, default packer/unpacker refer `MessagePack::DefaultFactory`. Call `MessagePack::DefaultFactory.register_type` to enable types process globally.
184
+
185
+ ```ruby
186
+ MessagePack::DefaultFactory.register_type(0x03, MyClass3)
187
+ MessagePack.unpack(data_with_ext_typeid_03) #=> MyClass3 instance
188
+ ```
189
+
190
+ ## Buffer API
191
+
192
+ MessagePack for Ruby provides a buffer API so that you can read or write data by hand, not via Packer or Unpacker API.
193
+
194
+ This [MessagePack::Buffer](http://ruby.msgpack.org/MessagePack/Buffer.html) is backed with a fixed-length shared memory pool which is very fast for small data (<= 4KB),
195
+ and has zero-copy capability which significantly affects performance to handle large binary data.
196
+
197
+ ## How to build and run tests
198
+
199
+ Before building msgpack, you need to install bundler and dependencies.
200
+
201
+ gem install bundler
202
+ bundle install
203
+
204
+ Then, you can run the tasks as follows:
205
+
206
+ ### Build
207
+
208
+ bundle exec rake build
209
+
210
+ ### Run tests
211
+
212
+ bundle exec rake spec
213
+
214
+ ### Generating docs
215
+
216
+ bundle exec rake doc
217
+
218
+ ## How to build -java rubygems
219
+
220
+ To build -java gems for JRuby, run:
221
+
222
+ rake build:java
223
+
224
+ If this directory has Gemfile.lock (generated with MRI), remove it beforehand.
225
+
226
+ ## Updating documents
227
+
228
+ Online documents (http://ruby.msgpack.org) is generated from gh-pages branch.
229
+ Following commands update documents in gh-pages branch:
230
+
231
+ bundle exec rake doc
232
+ git checkout gh-pages
233
+ cp doc/* ./ -a
234
+
235
+ ## Copyright
236
+
237
+ * Author
238
+ * Sadayuki Furuhashi <frsyuki@gmail.com>
239
+ * Copyright
240
+ * Copyright (c) 2008-2015 Sadayuki Furuhashi
241
+ * License
242
+ * Apache License, Version 2.0
data/Rakefile CHANGED
@@ -64,13 +64,6 @@ end
64
64
  namespace :build do
65
65
  desc 'Build gem for JRuby after cleaning'
66
66
  task :java => [:clean, :spec, :build]
67
-
68
- desc 'Build gems for Windows per rake-compiler-dock'
69
- task :windows do
70
- require 'rake_compiler_dock'
71
- # See RUBY_CC_VERSION in https://github.com/rake-compiler/rake-compiler-dock/blob/master/Dockerfile
72
- RakeCompilerDock.sh 'bundle && gem i json && rake cross native gem RUBY_CC_VERSION=2.2.2:2.3.0:2.4.0:2.5.0:2.6.0:2.7.0'
73
- end
74
67
  end
75
68
 
76
69
  CLEAN.include('lib/msgpack/msgpack.*')
@@ -38,36 +38,38 @@ public class Decoder implements Iterator<IRubyObject> {
38
38
  private ExtensionRegistry registry;
39
39
  private ByteBuffer buffer;
40
40
  private boolean symbolizeKeys;
41
+ private boolean freeze;
41
42
  private boolean allowUnknownExt;
42
43
 
43
44
  public Decoder(Ruby runtime) {
44
- this(runtime, null, new byte[] {}, 0, 0, false, false);
45
+ this(runtime, null, new byte[] {}, 0, 0, false, false, false);
45
46
  }
46
47
 
47
48
  public Decoder(Ruby runtime, ExtensionRegistry registry) {
48
- this(runtime, registry, new byte[] {}, 0, 0, false, false);
49
+ this(runtime, registry, new byte[] {}, 0, 0, false, false, false);
49
50
  }
50
51
 
51
52
  public Decoder(Ruby runtime, byte[] bytes) {
52
- this(runtime, null, bytes, 0, bytes.length, false, false);
53
+ this(runtime, null, bytes, 0, bytes.length, false, false, false);
53
54
  }
54
55
 
55
56
  public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes) {
56
- this(runtime, registry, bytes, 0, bytes.length, false, false);
57
+ this(runtime, registry, bytes, 0, bytes.length, false, false, false);
57
58
  }
58
59
 
59
- public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, boolean symbolizeKeys, boolean allowUnknownExt) {
60
- this(runtime, registry, bytes, 0, bytes.length, symbolizeKeys, allowUnknownExt);
60
+ public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, boolean symbolizeKeys, boolean freeze, boolean allowUnknownExt) {
61
+ this(runtime, registry, bytes, 0, bytes.length, symbolizeKeys, freeze, allowUnknownExt);
61
62
  }
62
63
 
63
64
  public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length) {
64
- this(runtime, registry, bytes, offset, length, false, false);
65
+ this(runtime, registry, bytes, offset, length, false, false, false);
65
66
  }
66
67
 
67
- public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length, boolean symbolizeKeys, boolean allowUnknownExt) {
68
+ public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length, boolean symbolizeKeys, boolean freeze, boolean allowUnknownExt) {
68
69
  this.runtime = runtime;
69
70
  this.registry = registry;
70
71
  this.symbolizeKeys = symbolizeKeys;
72
+ this.freeze = freeze;
71
73
  this.allowUnknownExt = allowUnknownExt;
72
74
  this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
73
75
  this.utf8Encoding = UTF8Encoding.INSTANCE;
@@ -118,7 +120,12 @@ public class Decoder implements Iterator<IRubyObject> {
118
120
  private IRubyObject consumeString(int size, Encoding encoding) {
119
121
  byte[] bytes = readBytes(size);
120
122
  ByteList byteList = new ByteList(bytes, encoding);
121
- return runtime.newString(byteList);
123
+ RubyString string = runtime.newString(byteList);
124
+ if (this.freeze) {
125
+ string.setFrozen(true);
126
+ string = runtime.freezeAndDedupString(string);
127
+ }
128
+ return string;
122
129
  }
123
130
 
124
131
  private IRubyObject consumeArray(int size) {
@@ -220,6 +227,14 @@ public class Decoder implements Iterator<IRubyObject> {
220
227
 
221
228
  @Override
222
229
  public IRubyObject next() {
230
+ IRubyObject next = consumeNext();
231
+ if (freeze) {
232
+ next.setFrozen(true);
233
+ }
234
+ return next;
235
+ }
236
+
237
+ private IRubyObject consumeNext() {
223
238
  int position = buffer.position();
224
239
  try {
225
240
  byte b = buffer.get();
@@ -34,6 +34,7 @@ public class Unpacker extends RubyObject {
34
34
  private Decoder decoder;
35
35
  private final RubyClass underflowErrorClass;
36
36
  private boolean symbolizeKeys;
37
+ private boolean freeze;
37
38
  private boolean allowUnknownExt;
38
39
 
39
40
  public Unpacker(Ruby runtime, RubyClass type) {
@@ -56,6 +57,7 @@ public class Unpacker extends RubyObject {
56
57
  public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
57
58
  symbolizeKeys = false;
58
59
  allowUnknownExt = false;
60
+ freeze = false;
59
61
  if (args.length > 0) {
60
62
  if (args[args.length - 1] instanceof RubyHash) {
61
63
  RubyHash options = (RubyHash) args[args.length - 1];
@@ -63,6 +65,10 @@ public class Unpacker extends RubyObject {
63
65
  if (sk != null) {
64
66
  symbolizeKeys = sk.isTrue();
65
67
  }
68
+ IRubyObject f = options.fastARef(ctx.getRuntime().newSymbol("freeze"));
69
+ if (f != null) {
70
+ freeze = f.isTrue();
71
+ }
66
72
  IRubyObject au = options.fastARef(ctx.getRuntime().newSymbol("allow_unknown_ext"));
67
73
  if (au != null) {
68
74
  allowUnknownExt = au.isTrue();
@@ -86,6 +92,11 @@ public class Unpacker extends RubyObject {
86
92
  return symbolizeKeys ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
87
93
  }
88
94
 
95
+ @JRubyMethod(name = "freeze?")
96
+ public IRubyObject isFreeze(ThreadContext ctx) {
97
+ return freeze ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
98
+ }
99
+
89
100
  @JRubyMethod(name = "allow_unknown_ext?")
90
101
  public IRubyObject isAllowUnknownExt(ThreadContext ctx) {
91
102
  return allowUnknownExt ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
@@ -144,7 +155,7 @@ public class Unpacker extends RubyObject {
144
155
  if (limit == -1) {
145
156
  limit = byteList.length() - offset;
146
157
  }
147
- Decoder decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, allowUnknownExt);
158
+ Decoder decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, freeze, allowUnknownExt);
148
159
  try {
149
160
  data = null;
150
161
  data = decoder.next();
@@ -174,7 +185,7 @@ public class Unpacker extends RubyObject {
174
185
  public IRubyObject feed(ThreadContext ctx, IRubyObject data) {
175
186
  ByteList byteList = data.asString().getByteList();
176
187
  if (decoder == null) {
177
- decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, allowUnknownExt);
188
+ decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
178
189
  } else {
179
190
  decoder.feed(byteList.unsafeBytes(), byteList.begin(), byteList.length());
180
191
  }
@@ -312,7 +323,7 @@ public class Unpacker extends RubyObject {
312
323
  ByteList byteList = str.getByteList();
313
324
  this.stream = stream;
314
325
  this.decoder = null;
315
- this.decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, allowUnknownExt);
326
+ this.decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
316
327
  return getStream(ctx);
317
328
  }
318
329
  }
data/ext/msgpack/buffer.c CHANGED
@@ -23,11 +23,11 @@
23
23
  static ID s_replace;
24
24
  #endif
25
25
 
26
- #ifdef COMPAT_HAVE_ENCODING /* see compat.h*/
27
26
  int msgpack_rb_encindex_utf8;
28
27
  int msgpack_rb_encindex_usascii;
29
28
  int msgpack_rb_encindex_ascii8bit;
30
- #endif
29
+
30
+ ID s_uminus;
31
31
 
32
32
  #ifndef DISABLE_RMEM
33
33
  static msgpack_rmem_t s_rmem;
@@ -35,11 +35,11 @@ static msgpack_rmem_t s_rmem;
35
35
 
36
36
  void msgpack_buffer_static_init()
37
37
  {
38
- #ifdef COMPAT_HAVE_ENCODING
38
+ s_uminus = rb_intern("-@");
39
+
39
40
  msgpack_rb_encindex_utf8 = rb_utf8_encindex();
40
41
  msgpack_rb_encindex_usascii = rb_usascii_encindex();
41
42
  msgpack_rb_encindex_ascii8bit = rb_ascii8bit_encindex();
42
- #endif
43
43
 
44
44
  #ifndef DISABLE_RMEM
45
45
  msgpack_rmem_init(&s_rmem);
@@ -308,9 +308,7 @@ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
308
308
  static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
309
309
  {
310
310
  VALUE mapped_string = rb_str_dup(string);
311
- #ifdef COMPAT_HAVE_ENCODING
312
311
  ENCODING_SET(mapped_string, msgpack_rb_encindex_ascii8bit);
313
- #endif
314
312
 
315
313
  _msgpack_buffer_add_new_chunk(b);
316
314
 
@@ -337,7 +335,6 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
337
335
 
338
336
  if(b->io != Qnil) {
339
337
  msgpack_buffer_flush(b);
340
- #ifdef COMPAT_HAVE_ENCODING
341
338
  if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
342
339
  rb_funcall(b->io, b->io_write_all_method, 1, string);
343
340
  } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
@@ -347,10 +344,6 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
347
344
  } else {
348
345
  msgpack_buffer_append(b, RSTRING_PTR(string), length);
349
346
  }
350
- #else
351
- rb_funcall(b->io, b->io_write_all_method, 1, string);
352
- #endif
353
-
354
347
  } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
355
348
  _msgpack_buffer_append_reference(b, string);
356
349