msgpack 1.3.3 → 1.7.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.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +99 -0
  3. data/README.md +293 -0
  4. data/ext/java/org/msgpack/jruby/Buffer.java +26 -19
  5. data/ext/java/org/msgpack/jruby/Decoder.java +46 -23
  6. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  7. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +43 -64
  8. data/ext/java/org/msgpack/jruby/ExtensionValue.java +6 -9
  9. data/ext/java/org/msgpack/jruby/Factory.java +43 -42
  10. data/ext/java/org/msgpack/jruby/Packer.java +37 -40
  11. data/ext/java/org/msgpack/jruby/Unpacker.java +86 -68
  12. data/ext/msgpack/buffer.c +58 -85
  13. data/ext/msgpack/buffer.h +59 -20
  14. data/ext/msgpack/buffer_class.c +161 -52
  15. data/ext/msgpack/buffer_class.h +1 -0
  16. data/ext/msgpack/compat.h +1 -111
  17. data/ext/msgpack/extconf.rb +41 -23
  18. data/ext/msgpack/factory_class.c +143 -87
  19. data/ext/msgpack/packer.c +66 -43
  20. data/ext/msgpack/packer.h +25 -27
  21. data/ext/msgpack/packer_class.c +102 -130
  22. data/ext/msgpack/packer_class.h +11 -0
  23. data/ext/msgpack/packer_ext_registry.c +35 -40
  24. data/ext/msgpack/packer_ext_registry.h +41 -38
  25. data/ext/msgpack/rbinit.c +1 -1
  26. data/ext/msgpack/rmem.c +3 -4
  27. data/ext/msgpack/sysdep.h +5 -2
  28. data/ext/msgpack/unpacker.c +130 -126
  29. data/ext/msgpack/unpacker.h +22 -13
  30. data/ext/msgpack/unpacker_class.c +94 -124
  31. data/ext/msgpack/unpacker_class.h +11 -0
  32. data/ext/msgpack/unpacker_ext_registry.c +40 -28
  33. data/ext/msgpack/unpacker_ext_registry.h +21 -18
  34. data/lib/msgpack/bigint.rb +69 -0
  35. data/lib/msgpack/buffer.rb +9 -0
  36. data/lib/msgpack/factory.rb +140 -10
  37. data/lib/msgpack/packer.rb +10 -1
  38. data/lib/msgpack/symbol.rb +21 -4
  39. data/lib/msgpack/time.rb +1 -1
  40. data/lib/msgpack/unpacker.rb +14 -1
  41. data/lib/msgpack/version.rb +4 -8
  42. data/lib/msgpack.rb +7 -12
  43. data/msgpack.gemspec +9 -8
  44. metadata +37 -96
  45. data/.gitignore +0 -23
  46. data/.rubocop.yml +0 -36
  47. data/.travis.yml +0 -43
  48. data/Gemfile +0 -9
  49. data/README.rdoc +0 -225
  50. data/Rakefile +0 -78
  51. data/appveyor.yml +0 -18
  52. data/bench/pack.rb +0 -23
  53. data/bench/pack_log.rb +0 -33
  54. data/bench/pack_log_long.rb +0 -65
  55. data/bench/pack_symbols.rb +0 -28
  56. data/bench/run.sh +0 -14
  57. data/bench/run_long.sh +0 -35
  58. data/bench/run_symbols.sh +0 -26
  59. data/bench/unpack.rb +0 -21
  60. data/bench/unpack_log.rb +0 -34
  61. data/bench/unpack_log_long.rb +0 -67
  62. data/doclib/msgpack/buffer.rb +0 -193
  63. data/doclib/msgpack/core_ext.rb +0 -101
  64. data/doclib/msgpack/error.rb +0 -19
  65. data/doclib/msgpack/extension_value.rb +0 -9
  66. data/doclib/msgpack/factory.rb +0 -101
  67. data/doclib/msgpack/packer.rb +0 -208
  68. data/doclib/msgpack/time.rb +0 -22
  69. data/doclib/msgpack/timestamp.rb +0 -44
  70. data/doclib/msgpack/unpacker.rb +0 -183
  71. data/doclib/msgpack.rb +0 -87
  72. data/msgpack.org.md +0 -46
  73. data/spec/cases.json +0 -1
  74. data/spec/cases.msg +0 -0
  75. data/spec/cases_compact.msg +0 -0
  76. data/spec/cases_spec.rb +0 -39
  77. data/spec/cruby/buffer_io_spec.rb +0 -255
  78. data/spec/cruby/buffer_packer.rb +0 -29
  79. data/spec/cruby/buffer_spec.rb +0 -575
  80. data/spec/cruby/buffer_unpacker.rb +0 -19
  81. data/spec/cruby/unpacker_spec.rb +0 -70
  82. data/spec/ext_value_spec.rb +0 -99
  83. data/spec/exttypes.rb +0 -51
  84. data/spec/factory_spec.rb +0 -367
  85. data/spec/format_spec.rb +0 -301
  86. data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
  87. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
  88. data/spec/jruby/unpacker_spec.rb +0 -186
  89. data/spec/msgpack_spec.rb +0 -214
  90. data/spec/pack_spec.rb +0 -61
  91. data/spec/packer_spec.rb +0 -557
  92. data/spec/random_compat.rb +0 -24
  93. data/spec/spec_helper.rb +0 -38
  94. data/spec/timestamp_spec.rb +0 -121
  95. data/spec/unpack_spec.rb +0 -57
  96. data/spec/unpacker_spec.rb +0 -716
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40d206a80a2ab99957b78f2d054417dc273933da4accf5f39a25ff4b16ec30ce
4
- data.tar.gz: e39c06187017d057a44e71d3690662455934c2c1acafc667d49e91aaf626fbd9
3
+ metadata.gz: 2f5b1af6b3a51f5ccc6bcf67c94c1fc6193b02fe01b123e2cfb06a6df9607116
4
+ data.tar.gz: cc057f24e1ffa4cdc3e331499eb04de4c2383b0657dcf0baeba08300fd20862e
5
5
  SHA512:
6
- metadata.gz: d20c8da71f90435f264c0e1c9c90e4a5c8c09c014d33076149e6e5faa3b849ac5192d2f086b917f09eb199bcfd8cc748093d6f59e3f5fcb7c228199f549c23c5
7
- data.tar.gz: dd5c662d5abbf45901d59a7400f2b92a6c296b2298035fecc55a31f82b19b4e9206ca3b0a7cab090d9cc9768bea015b74ad9bf5a997a763eb6ba3387b6a7fc30
6
+ metadata.gz: 3eb06321a534ca9b16e321cc4a71458532578dafe7967314a662223b1fbf4aa93449c98177fa982aa532ce3732ddda4a6d497704df0e9c874da07f378c73595c
7
+ data.tar.gz: 8e540755e3db9e21d7dfa4354854e8b0486f5a1bbf82c3994c6095022205f7873153d364df9310d8072c481de38ca2b4c3e088e4221c3451ceb9438312489419
data/ChangeLog CHANGED
@@ -1,3 +1,102 @@
1
+ 2023-07-18 1.7.2:
2
+
3
+ * Fix a potential GC bug when packing data using recursive extensions and buffers containing over 512KkiB of data (See #341).
4
+ * Fix a regression where feeding an empty string to an Unpacker would be considered like the end of the buffer.
5
+
6
+ 2023-05-19 1.7.1:
7
+
8
+ * Fix JRuby 9.4 compatibility.
9
+ * Fix compilation on older compilers (gcc 4.x).
10
+ * Fix an infinite recursion issue when registering a Symbol type with a `nil` packer.
11
+
12
+ 2023-03-29 1.7.0:
13
+
14
+ * Fix a possible double-free issue when GC triggers inside `_msgpack_rmem_alloc2`.
15
+ * `Unpacker#feed` now always directly read in provided strings instead of copying content in its buffer.
16
+ * `Unpacker#feed` is now an alias of `Unpacker#feed_reference`.
17
+ * Implement `Factory::Pool#unpacker` and `Factory::Pool#packer` to allow for more precise serialization.
18
+ * Require Ruby 2.5+.
19
+
20
+ 2023-03-03 1.6.1:
21
+
22
+ * Undefine `#clone` and `#dup` on `MessagePack::Buffer`, `MessagePack::Packer` and `MessagePack::Unpacker`.
23
+ These methods were never intended, and using them could cause leaks or crashes or worse.
24
+ * Fix a possible GC crash when GC trigger inside `MessagePack::Buffer.new` (#314).
25
+
26
+ 2022-09-30 1.6.0:
27
+
28
+ * Fix a potential use-after-free bug in Buffer_free when accessing a packer or unpacker buffer.
29
+ * `old-style-definition` compilation warnings.
30
+ * Restore zero-copy buffer feed when provided a Ruby string. This was accidentally broken in 1.5.4.
31
+ * Provide implementations for `ObjectSpace.memsize`. Message pack objects now properly report their size to Ruby.
32
+ * Fix an endianess bug on Windows platform.
33
+
34
+ 2022-08-23 1.5.6:
35
+
36
+ * No actual code change, just re-release the `java` version properly.
37
+
38
+ 2022-08-22 1.5.5:
39
+
40
+ * Fix a segfault when GC triggers inside a recursive extension.
41
+
42
+ 2022-07-25 1.5.4:
43
+
44
+ * Fix a segfault when deserializing empty symbol (`:""`).
45
+ * Improve compilation flags to not strip debug symbols.
46
+
47
+ 2022-05-30 version 1.5.3:
48
+
49
+ * Fix deduplication of empty strings when using the `freeze: true` option.
50
+ * Use `rb_hash_new_capa` when available (Ruby 3.2) for improved performance when parsing large hashes.
51
+
52
+ 2022-05-27 version 1.5.2:
53
+
54
+ * Fix bug about unpacking ext type objects with the recursive option
55
+
56
+ 2022-04-07 version 1.5.1:
57
+
58
+ * Fix bug about packing/unpacking ext type objects with the recursive option
59
+
60
+ 2022-04-06 version 1.5.0:
61
+
62
+ * Add recursive option on Factory#register_type to operate Packer/Unpacker manually
63
+ * Add oversized_integer_extension option on Factory#register_type to pack/unpack bigint using ext types
64
+ * Add Factory#pool method and Factory::Pool class to provide pooled Packer and Unpacker instances
65
+
66
+ 2022-02-15 version 1.4.5:
67
+
68
+ * Fix to create UTF-8 Symbol keys when symbolize_keys: true
69
+ * Fix to assume Symbols as US-ASCII or UTF-8
70
+ * Optimize Packer/Unpacker initialization
71
+ * Optimize extension class lookup
72
+ * Rename Packer#clear as Packer#reset (#clear is still available as an alias)
73
+
74
+ 2022-01-22 version 1.4.4:
75
+
76
+ * Specify the build option --platform=8 for older Java platforms
77
+
78
+ 2022-01-20 version 1.4.3:
79
+
80
+ * Optimize serialization/deserialization of Symbols
81
+ * Support registering ext types for objects of subclasses of primitive types (like Hash)
82
+ * Add optimized_symbols_parsing option to Factory#register_type on MRI implementation
83
+ * Optimize to deduplicate Hash keys on JRuby
84
+ * Support JRuby 9.3 (and drop 9.1)
85
+
86
+ 2021-02-01 version 1.4.2:
87
+
88
+ * Add the required Ruby version (>= 2.4) to avoid compilation errors on older Ruby runtimes
89
+ * Drop the support of old Ruby versions explicitly (1.8, 1.9, 2.0, 2.1, 2.2, 2.3)
90
+
91
+ 2021-01-27 version 1.4.1:
92
+
93
+ * Bugfix about the wrong string encoding longer than 256 bytes (#200)
94
+
95
+ 2021-01-27 version 1.4.0:
96
+
97
+ * Introduce the optimization to use frozen/deduped keys for map objects
98
+ * Stop releasing fat gem (pre-built binaries) for mswin32 arch environments
99
+
1
100
  2020-02-05 version 1.3.3:
2
101
 
3
102
  * Hotfix release for Windows environments: 1.3.2 missed including binaries
data/README.md ADDED
@@ -0,0 +1,293 @@
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 are 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
+ File.binwrite('mydata.msgpack', msg)
55
+ ```
56
+
57
+ ### Streaming serialization
58
+
59
+ Packer provides advanced API to serialize objects in streaming style:
60
+
61
+ ```ruby
62
+ # serialize a 2-element array [e1, e2]
63
+ pk = MessagePack::Packer.new(io)
64
+ pk.write_array_header(2).write(e1).write(e2).flush
65
+ ```
66
+
67
+ See [API reference](http://ruby.msgpack.org/MessagePack/Packer.html) for details.
68
+
69
+ ## Deserializing objects
70
+
71
+ Use `MessagePack.unpack`:
72
+
73
+ ```ruby
74
+ require 'msgpack'
75
+ msg = File.binread('mydata.msgpack')
76
+ obj = MessagePack.unpack(msg)
77
+ ```
78
+
79
+ ### Streaming deserialization
80
+
81
+ Unpacker provides advanced API to deserialize objects in streaming style:
82
+
83
+ ```ruby
84
+ # deserialize objects from an IO
85
+ u = MessagePack::Unpacker.new(io)
86
+ u.each do |obj|
87
+ # ...
88
+ end
89
+ ```
90
+
91
+ or event-driven style which works well with EventMachine:
92
+
93
+ ```ruby
94
+ # event-driven deserialization
95
+ def on_read(data)
96
+ @u ||= MessagePack::Unpacker.new
97
+ @u.feed_each(data) {|obj|
98
+ # ...
99
+ }
100
+ end
101
+ ```
102
+
103
+ See [API reference](http://ruby.msgpack.org/MessagePack/Unpacker.html) for details.
104
+
105
+ ## Serializing and deserializing symbols
106
+
107
+ By default, symbols are serialized as strings:
108
+
109
+ ```ruby
110
+ packed = :symbol.to_msgpack # => "\xA6symbol"
111
+ MessagePack.unpack(packed) # => "symbol"
112
+ ```
113
+
114
+ This can be customized by registering an extension type for them:
115
+
116
+ ```ruby
117
+ MessagePack::DefaultFactory.register_type(0x00, Symbol)
118
+
119
+ # symbols now survive round trips
120
+ packed = :symbol.to_msgpack # => "\xc7\x06\x00symbol"
121
+ MessagePack.unpack(packed) # => :symbol
122
+ ```
123
+
124
+ The extension type for symbols is configurable like any other extension type.
125
+ For example, to customize how symbols are packed you can just redefine
126
+ Symbol#to_msgpack_ext. Doing this gives you an option to prevent symbols from
127
+ being serialized altogether by throwing an exception:
128
+
129
+ ```ruby
130
+ class Symbol
131
+ def to_msgpack_ext
132
+ raise "Serialization of symbols prohibited"
133
+ end
134
+ end
135
+
136
+ MessagePack::DefaultFactory.register_type(0x00, Symbol)
137
+
138
+ [1, :symbol, 'string'].to_msgpack # => RuntimeError: Serialization of symbols prohibited
139
+ ```
140
+
141
+ ## Serializing and deserializing Time instances
142
+
143
+ There are the timestamp extension type in MessagePack,
144
+ but it is not registered by default.
145
+
146
+ To map Ruby's Time to MessagePack's timestamp for the default factory:
147
+
148
+ ```ruby
149
+ MessagePack::DefaultFactory.register_type(
150
+ MessagePack::Timestamp::TYPE, # or just -1
151
+ Time,
152
+ packer: MessagePack::Time::Packer,
153
+ unpacker: MessagePack::Time::Unpacker
154
+ )
155
+ ```
156
+
157
+ See [API reference](http://ruby.msgpack.org/) for details.
158
+
159
+ ## Extension Types
160
+
161
+ Packer and Unpacker support [Extension types of MessagePack](https://github.com/msgpack/msgpack/blob/master/spec.md#types-extension-type).
162
+
163
+ ```ruby
164
+ # register how to serialize custom class at first
165
+ pk = MessagePack::Packer.new(io)
166
+ pk.register_type(0x01, MyClass1, :to_msgpack_ext) # equal to pk.register_type(0x01, MyClass)
167
+ pk.register_type(0x02, MyClass2){|obj| obj.how_to_serialize() } # blocks also available
168
+
169
+ # almost same API for unpacker
170
+ uk = MessagePack::Unpacker.new()
171
+ uk.register_type(0x01, MyClass1, :from_msgpack_ext)
172
+ uk.register_type(0x02){|data| MyClass2.create_from_serialized_data(data) }
173
+ ```
174
+
175
+ `MessagePack::Factory` is to create packer and unpacker which have same extension types.
176
+
177
+ ```ruby
178
+ factory = MessagePack::Factory.new
179
+ factory.register_type(0x01, MyClass1) # same with next line
180
+ factory.register_type(0x01, MyClass1, packer: :to_msgpack_ext, unpacker: :from_msgpack_ext)
181
+ pk = factory.packer(options_for_packer)
182
+ uk = factory.unpacker(options_for_unpacker)
183
+ ```
184
+
185
+ For `MessagePack.pack` and `MessagePack.unpack`, default packer/unpacker refer `MessagePack::DefaultFactory`. Call `MessagePack::DefaultFactory.register_type` to enable types process globally.
186
+
187
+ ```ruby
188
+ MessagePack::DefaultFactory.register_type(0x03, MyClass3)
189
+ MessagePack.unpack(data_with_ext_typeid_03) #=> MyClass3 instance
190
+ ```
191
+
192
+ Alternatively, extension types can call the packer or unpacker recursively to generate the extension data:
193
+
194
+ ```ruby
195
+ Point = Struct.new(:x, :y)
196
+ factory = MessagePack::Factory.new
197
+ factory.register_type(
198
+ 0x01,
199
+ Point,
200
+ packer: ->(point, packer) {
201
+ packer.write(point.x)
202
+ packer.write(point.y)
203
+ },
204
+ unpacker: ->(unpacker) {
205
+ x = unpacker.read
206
+ y = unpacker.read
207
+ Point.new(x, y)
208
+ },
209
+ recursive: true,
210
+ )
211
+ factory.load(factory.dump(Point.new(12, 34))) # => #<struct Point x=12, y=34>
212
+ ```
213
+
214
+ ## Pooling
215
+
216
+ Creating `Packer` and `Unpacker` objects is expensive. For best performance it is preferable to re-use these objects.
217
+
218
+ `MessagePack::Factory#pool` makes that easier:
219
+
220
+ ```ruby
221
+ factory = MessagePack::Factory.new
222
+ factory.register_type(
223
+ 0x01,
224
+ Point,
225
+ packer: ->(point, packer) {
226
+ packer.write(point.x)
227
+ packer.write(point.y)
228
+ },
229
+ unpacker: ->(unpacker) {
230
+ x = unpacker.read
231
+ y = unpacker.read
232
+ Point.new(x, y)
233
+ },
234
+ recursive: true,
235
+ )
236
+ pool = factory.pool(5) # The pool size should match the number of threads expected to use the factory concurrently.
237
+
238
+ pool.load(pool.dump(Point.new(12, 34))) # => #<struct Point x=12, y=34>
239
+ ```
240
+
241
+ ## Buffer API
242
+
243
+ MessagePack for Ruby provides a buffer API so that you can read or write data by hand, not via Packer or Unpacker API.
244
+
245
+ 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),
246
+ and has zero-copy capability which significantly affects performance to handle large binary data.
247
+
248
+ ## How to build and run tests
249
+
250
+ Before building msgpack, you need to install bundler and dependencies.
251
+
252
+ gem install bundler
253
+ bundle install
254
+
255
+ Then, you can run the tasks as follows:
256
+
257
+ ### Build
258
+
259
+ bundle exec rake build
260
+
261
+ ### Run tests
262
+
263
+ bundle exec rake spec
264
+
265
+ ### Generating docs
266
+
267
+ bundle exec rake doc
268
+
269
+ ## How to build -java rubygems
270
+
271
+ To build -java gems for JRuby, run:
272
+
273
+ rake build:java
274
+
275
+ If this directory has Gemfile.lock (generated with MRI), remove it beforehand.
276
+
277
+ ## Updating documents
278
+
279
+ Online documents (http://ruby.msgpack.org) is generated from gh-pages branch.
280
+ Following commands update documents in gh-pages branch:
281
+
282
+ bundle exec rake doc
283
+ git checkout gh-pages
284
+ cp doc/* ./ -a
285
+
286
+ ## Copyright
287
+
288
+ * Author
289
+ * Sadayuki Furuhashi <frsyuki@gmail.com>
290
+ * Copyright
291
+ * Copyright (c) 2008-2015 Sadayuki Furuhashi
292
+ * License
293
+ * Apache License, Version 2.0
@@ -21,10 +21,11 @@ import org.jcodings.Encoding;
21
21
 
22
22
  @JRubyClass(name="MessagePack::Buffer")
23
23
  public class Buffer extends RubyObject {
24
- private IRubyObject io;
25
- private ByteBuffer buffer;
24
+ private static final long serialVersionUID = 8441244627425629412L;
25
+ private transient IRubyObject io;
26
+ private transient ByteBuffer buffer;
26
27
  private boolean writeMode;
27
- private Encoding binaryEncoding;
28
+ private transient Encoding binaryEncoding;
28
29
 
29
30
  private static final int CACHE_LINE_SIZE = 64;
30
31
  private static final int ARRAY_HEADER_SIZE = 24;
@@ -49,7 +50,7 @@ public class Buffer extends RubyObject {
49
50
  }
50
51
  this.buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE);
51
52
  this.writeMode = true;
52
- this.binaryEncoding = ctx.getRuntime().getEncodingService().getAscii8bitEncoding();
53
+ this.binaryEncoding = ctx.runtime.getEncodingService().getAscii8bitEncoding();
53
54
  return this;
54
55
  }
55
56
 
@@ -87,17 +88,17 @@ public class Buffer extends RubyObject {
87
88
  writeMode = true;
88
89
  }
89
90
  buffer.clear();
90
- return ctx.getRuntime().getNil();
91
+ return ctx.runtime.getNil();
91
92
  }
92
93
 
93
94
  @JRubyMethod(name = "size")
94
95
  public IRubyObject size(ThreadContext ctx) {
95
- return ctx.getRuntime().newFixnum(rawSize());
96
+ return ctx.runtime.newFixnum(rawSize());
96
97
  }
97
98
 
98
99
  @JRubyMethod(name = "empty?")
99
100
  public IRubyObject isEmpty(ThreadContext ctx) {
100
- return rawSize() == 0 ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
101
+ return rawSize() == 0 ? ctx.runtime.getTrue() : ctx.runtime.getFalse();
101
102
  }
102
103
 
103
104
  private IRubyObject bufferWrite(ThreadContext ctx, IRubyObject str) {
@@ -105,7 +106,7 @@ public class Buffer extends RubyObject {
105
106
  int length = bytes.length();
106
107
  ensureRemainingCapacity(length);
107
108
  buffer.put(bytes.unsafeBytes(), bytes.begin(), length);
108
- return ctx.getRuntime().newFixnum(length);
109
+ return ctx.runtime.newFixnum(length);
109
110
 
110
111
  }
111
112
 
@@ -131,19 +132,19 @@ public class Buffer extends RubyObject {
131
132
  length = (int) args[0].convertToInteger().getLongValue();
132
133
  }
133
134
  if (raiseOnUnderflow && rawSize() < length) {
134
- throw ctx.getRuntime().newEOFError();
135
+ throw ctx.runtime.newEOFError();
135
136
  }
136
137
  int readLength = Math.min(length, rawSize());
137
138
  if (readLength == 0 && length > 0) {
138
- return ctx.getRuntime().getNil();
139
+ return ctx.runtime.getNil();
139
140
  } else if (readLength == 0) {
140
- return ctx.getRuntime().newString();
141
+ return ctx.runtime.newString();
141
142
  } else {
142
143
  ensureReadMode();
143
144
  byte[] bytes = new byte[readLength];
144
145
  buffer.get(bytes);
145
146
  ByteList byteList = new ByteList(bytes, binaryEncoding);
146
- return ctx.getRuntime().newString(byteList);
147
+ return ctx.runtime.newString(byteList);
147
148
  }
148
149
  }
149
150
 
@@ -161,12 +162,12 @@ public class Buffer extends RubyObject {
161
162
  feed(ctx);
162
163
  int length = (int) _length.convertToInteger().getLongValue();
163
164
  if (raiseOnUnderflow && rawSize() < length) {
164
- throw ctx.getRuntime().newEOFError();
165
+ throw ctx.runtime.newEOFError();
165
166
  }
166
167
  ensureReadMode();
167
168
  int skipLength = Math.min(length, rawSize());
168
169
  buffer.position(buffer.position() + skipLength);
169
- return ctx.getRuntime().newFixnum(skipLength);
170
+ return ctx.runtime.newFixnum(skipLength);
170
171
  }
171
172
 
172
173
  @JRubyMethod(name = "skip")
@@ -188,23 +189,23 @@ public class Buffer extends RubyObject {
188
189
  ensureReadMode();
189
190
  int length = buffer.limit() - buffer.position();
190
191
  ByteList str = new ByteList(buffer.array(), buffer.position(), length, binaryEncoding, true);
191
- return ctx.getRuntime().newString(str);
192
+ return ctx.runtime.newString(str);
192
193
  }
193
194
 
194
195
  @JRubyMethod(name = "to_a")
195
196
  public IRubyObject toA(ThreadContext ctx) {
196
- return ctx.getRuntime().newArray(toS(ctx));
197
+ return ctx.runtime.newArray(toS(ctx));
197
198
  }
198
199
 
199
200
  @JRubyMethod(name = "io")
200
201
  public IRubyObject getIo(ThreadContext ctx) {
201
- return io == null ? ctx.getRuntime().getNil() : io;
202
+ return io == null ? ctx.runtime.getNil() : io;
202
203
  }
203
204
 
204
205
  @JRubyMethod(name = "flush")
205
206
  public IRubyObject flush(ThreadContext ctx) {
206
207
  if (io == null) {
207
- return ctx.getRuntime().getNil();
208
+ return ctx.runtime.getNil();
208
209
  } else {
209
210
  return io.callMethod(ctx, "flush");
210
211
  }
@@ -213,7 +214,7 @@ public class Buffer extends RubyObject {
213
214
  @JRubyMethod(name = "close")
214
215
  public IRubyObject close(ThreadContext ctx) {
215
216
  if (io == null) {
216
- return ctx.getRuntime().getNil();
217
+ return ctx.runtime.getNil();
217
218
  } else {
218
219
  return io.callMethod(ctx, "close");
219
220
  }
@@ -223,4 +224,10 @@ public class Buffer extends RubyObject {
223
224
  public IRubyObject writeTo(ThreadContext ctx, IRubyObject io) {
224
225
  return io.callMethod(ctx, "write", readCommon(ctx, null, false));
225
226
  }
227
+
228
+ public ByteList getBytes() {
229
+ byte[] bytes = new byte[rawSize()];
230
+ buffer.get(bytes);
231
+ return new ByteList(bytes, binaryEncoding);
232
+ }
226
233
  }
@@ -14,6 +14,7 @@ import org.jruby.RubyBignum;
14
14
  import org.jruby.RubyString;
15
15
  import org.jruby.RubyArray;
16
16
  import org.jruby.RubyHash;
17
+ import org.jruby.RubyInteger;
17
18
  import org.jruby.exceptions.RaiseException;
18
19
  import org.jruby.runtime.builtin.IRubyObject;
19
20
  import org.jruby.util.ByteList;
@@ -35,39 +36,41 @@ public class Decoder implements Iterator<IRubyObject> {
35
36
  private final RubyClass unexpectedTypeErrorClass;
36
37
  private final RubyClass unknownExtTypeErrorClass;
37
38
 
38
- private ExtensionRegistry registry;
39
+ private Unpacker unpacker;
39
40
  private ByteBuffer buffer;
40
41
  private boolean symbolizeKeys;
42
+ private boolean freeze;
41
43
  private boolean allowUnknownExt;
42
44
 
43
45
  public Decoder(Ruby runtime) {
44
- this(runtime, null, new byte[] {}, 0, 0, false, false);
46
+ this(runtime, null, new byte[] {}, 0, 0, false, false, false);
45
47
  }
46
48
 
47
- public Decoder(Ruby runtime, ExtensionRegistry registry) {
48
- this(runtime, registry, new byte[] {}, 0, 0, false, false);
49
+ public Decoder(Ruby runtime, Unpacker unpacker) {
50
+ this(runtime, unpacker, new byte[] {}, 0, 0, false, false, false);
49
51
  }
50
52
 
51
53
  public Decoder(Ruby runtime, byte[] bytes) {
52
- this(runtime, null, bytes, 0, bytes.length, false, false);
54
+ this(runtime, null, bytes, 0, bytes.length, false, false, false);
53
55
  }
54
56
 
55
- public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes) {
56
- this(runtime, registry, bytes, 0, bytes.length, false, false);
57
+ public Decoder(Ruby runtime, Unpacker unpacker, byte[] bytes) {
58
+ this(runtime, unpacker, bytes, 0, bytes.length, false, false, false);
57
59
  }
58
60
 
59
- public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, boolean symbolizeKeys, boolean allowUnknownExt) {
60
- this(runtime, registry, bytes, 0, bytes.length, symbolizeKeys, allowUnknownExt);
61
+ public Decoder(Ruby runtime, Unpacker unpacker, byte[] bytes, boolean symbolizeKeys, boolean freeze, boolean allowUnknownExt) {
62
+ this(runtime, unpacker, bytes, 0, bytes.length, symbolizeKeys, freeze, allowUnknownExt);
61
63
  }
62
64
 
63
- public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length) {
64
- this(runtime, registry, bytes, offset, length, false, false);
65
+ public Decoder(Ruby runtime, Unpacker unpacker, byte[] bytes, int offset, int length) {
66
+ this(runtime, unpacker, bytes, offset, length, false, false, false);
65
67
  }
66
68
 
67
- public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length, boolean symbolizeKeys, boolean allowUnknownExt) {
69
+ public Decoder(Ruby runtime, Unpacker unpacker, byte[] bytes, int offset, int length, boolean symbolizeKeys, boolean freeze, boolean allowUnknownExt) {
68
70
  this.runtime = runtime;
69
- this.registry = registry;
71
+ this.unpacker = unpacker;
70
72
  this.symbolizeKeys = symbolizeKeys;
73
+ this.freeze = freeze;
71
74
  this.allowUnknownExt = allowUnknownExt;
72
75
  this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
73
76
  this.utf8Encoding = UTF8Encoding.INSTANCE;
@@ -118,7 +121,11 @@ public class Decoder implements Iterator<IRubyObject> {
118
121
  private IRubyObject consumeString(int size, Encoding encoding) {
119
122
  byte[] bytes = readBytes(size);
120
123
  ByteList byteList = new ByteList(bytes, encoding);
121
- return runtime.newString(byteList);
124
+ RubyString string = runtime.newString(byteList);
125
+ if (this.freeze) {
126
+ string = runtime.freezeAndDedupString(string);
127
+ }
128
+ return string;
122
129
  }
123
130
 
124
131
  private IRubyObject consumeArray(int size) {
@@ -133,9 +140,14 @@ public class Decoder implements Iterator<IRubyObject> {
133
140
  RubyHash hash = RubyHash.newHash(runtime);
134
141
  for (int i = 0; i < size; i++) {
135
142
  IRubyObject key = next();
136
- if (this.symbolizeKeys && key instanceof RubyString) {
143
+ if (key instanceof RubyString) {
144
+ if (this.symbolizeKeys) {
137
145
  key = ((RubyString) key).intern();
146
+ } else {
147
+ key = runtime.freezeAndDedupString((RubyString) key);
148
+ }
138
149
  }
150
+
139
151
  hash.fastASet(key, next());
140
152
  }
141
153
  return hash;
@@ -143,18 +155,21 @@ public class Decoder implements Iterator<IRubyObject> {
143
155
 
144
156
  private IRubyObject consumeExtension(int size) {
145
157
  int type = buffer.get();
146
- byte[] payload = readBytes(size);
147
-
148
- if (registry != null) {
149
- IRubyObject proc = registry.lookupUnpackerByTypeId(type);
150
- if (proc != null) {
151
- ByteList byteList = new ByteList(payload, runtime.getEncodingService().getAscii8bitEncoding());
152
- return proc.callMethod(runtime.getCurrentContext(), "call", runtime.newString(byteList));
158
+ if (unpacker != null) {
159
+ ExtensionRegistry.ExtensionEntry entry = unpacker.lookupExtensionByTypeId(type);
160
+ if (entry != null) {
161
+ IRubyObject proc = entry.getUnpackerProc();
162
+ if (entry.isRecursive()) {
163
+ return proc.callMethod(runtime.getCurrentContext(), "call", unpacker);
164
+ } else {
165
+ ByteList byteList = new ByteList(readBytes(size), runtime.getEncodingService().getAscii8bitEncoding());
166
+ return proc.callMethod(runtime.getCurrentContext(), "call", runtime.newString(byteList));
167
+ }
153
168
  }
154
169
  }
155
170
 
156
171
  if (this.allowUnknownExt) {
157
- return ExtensionValue.newExtensionValue(runtime, type, payload);
172
+ return ExtensionValue.newExtensionValue(runtime, type, readBytes(size));
158
173
  }
159
174
 
160
175
  throw runtime.newRaiseException(unknownExtTypeErrorClass, "unexpected extension type");
@@ -220,6 +235,14 @@ public class Decoder implements Iterator<IRubyObject> {
220
235
 
221
236
  @Override
222
237
  public IRubyObject next() {
238
+ IRubyObject next = consumeNext();
239
+ if (freeze) {
240
+ next.setFrozen(true);
241
+ }
242
+ return next;
243
+ }
244
+
245
+ private IRubyObject consumeNext() {
223
246
  int position = buffer.position();
224
247
  try {
225
248
  byte b = buffer.get();