msgpack 1.4.0.pre1 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
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