msgpack 1.4.4 → 1.5.1
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 +4 -4
- data/.github/workflows/ci.yaml +4 -3
- data/ChangeLog +18 -0
- data/README.md +22 -0
- data/doclib/msgpack/factory.rb +46 -3
- data/doclib/msgpack/packer.rb +5 -4
- data/doclib/msgpack/unpacker.rb +2 -2
- data/ext/java/org/msgpack/jruby/Buffer.java +6 -0
- data/ext/java/org/msgpack/jruby/Decoder.java +23 -19
- data/ext/java/org/msgpack/jruby/Encoder.java +46 -18
- data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +28 -40
- data/ext/java/org/msgpack/jruby/Factory.java +40 -5
- data/ext/java/org/msgpack/jruby/Packer.java +21 -11
- data/ext/java/org/msgpack/jruby/Unpacker.java +44 -22
- data/ext/msgpack/buffer.h +2 -2
- data/ext/msgpack/buffer_class.c +23 -15
- data/ext/msgpack/factory_class.c +78 -16
- data/ext/msgpack/packer.c +42 -5
- data/ext/msgpack/packer.h +24 -0
- data/ext/msgpack/packer_class.c +29 -22
- data/ext/msgpack/packer_ext_registry.c +23 -9
- data/ext/msgpack/packer_ext_registry.h +38 -31
- data/ext/msgpack/unpacker.c +72 -32
- data/ext/msgpack/unpacker.h +2 -2
- data/ext/msgpack/unpacker_class.c +26 -45
- data/ext/msgpack/unpacker_ext_registry.c +40 -16
- data/ext/msgpack/unpacker_ext_registry.h +21 -14
- data/lib/msgpack/bigint.rb +69 -0
- data/lib/msgpack/factory.rb +103 -0
- data/lib/msgpack/symbol.rb +8 -1
- data/lib/msgpack/version.rb +1 -1
- data/lib/msgpack.rb +4 -5
- data/spec/bigint_spec.rb +26 -0
- data/spec/factory_spec.rb +284 -14
- data/spec/spec_helper.rb +4 -4
- data/spec/timestamp_spec.rb +0 -2
- data/spec/unpacker_spec.rb +22 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c5ae461c691018c21ea088c4b629510c0626a31c16e640d7128d1d4be70276a
|
4
|
+
data.tar.gz: 32ac330fedeb8fdcf90e172df4480d05564185ef9b3e72f430c83de04eea90b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a5a1c96cbfdc2030c38cf559a61aaacc466a5b4fcaaa6af809b8d062f3042a44ee6df0f731fe77bbdf1ebba0a123da2b9db033e7117baabcc6e9664dd6f56ef
|
7
|
+
data.tar.gz: 07c313bd70f92996b0131a0c5ce9836f025dd4fa98fdbe365ad04fa860b2bd6ca81c62fbd90cc2296a75eddd2a9b648b3ca48b8838a40ffab72a5845dfd6e724
|
data/.github/workflows/ci.yaml
CHANGED
@@ -12,6 +12,7 @@ on:
|
|
12
12
|
jobs:
|
13
13
|
mri:
|
14
14
|
strategy:
|
15
|
+
fail-fast: false
|
15
16
|
matrix:
|
16
17
|
os: [ubuntu, macos, windows]
|
17
18
|
ruby: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1']
|
@@ -26,11 +27,10 @@ jobs:
|
|
26
27
|
|
27
28
|
jruby:
|
28
29
|
strategy:
|
30
|
+
fail-fast: false
|
29
31
|
matrix:
|
30
32
|
os: [ubuntu]
|
31
|
-
|
32
|
-
# https://github.com/ruby/setup-ruby#supported-versions
|
33
|
-
ruby: ['jruby-9.2.19.0', 'jruby-9.3.2.0']
|
33
|
+
ruby: ['jruby-9.2.19.0', 'jruby-9.3.3.0']
|
34
34
|
runs-on: ${{ matrix.os }}-latest
|
35
35
|
steps:
|
36
36
|
- uses: actions/checkout@v2
|
@@ -43,6 +43,7 @@ jobs:
|
|
43
43
|
head-versions:
|
44
44
|
continue-on-error: true
|
45
45
|
strategy:
|
46
|
+
fail-fast: false
|
46
47
|
matrix:
|
47
48
|
os: [ubuntu]
|
48
49
|
ruby: ['ruby-head', 'jruby-head', 'truffleruby']
|
data/ChangeLog
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
2022-04-07 version 1.5.1:
|
2
|
+
|
3
|
+
* Fix bug about packing/unpacking ext type objects with the recursive option
|
4
|
+
|
5
|
+
2022-04-06 version 1.5.0:
|
6
|
+
|
7
|
+
* Add recursive option on Factory#register_type to operate Packer/Unpacker manually
|
8
|
+
* Add oversized_integer_extension option on Factory#register_type to pack/unpack bigint using ext types
|
9
|
+
* Add Factory#pool method and Factory::Pool class to provide pooled Packer and Unpacker instances
|
10
|
+
|
11
|
+
2022-02-15 version 1.4.5:
|
12
|
+
|
13
|
+
* Fix to create UTF-8 Symbol keys when symbolize_keys: true
|
14
|
+
* Fix to assume Symbols as US-ASCII or UTF-8
|
15
|
+
* Optimize Packer/Unpacker initialization
|
16
|
+
* Optimize extension class lookup
|
17
|
+
* Rename Packer#clear as Packer#reset (#clear is still available as an alias)
|
18
|
+
|
1
19
|
2022-01-22 version 1.4.4:
|
2
20
|
|
3
21
|
* Specify the build option --platform=8 for older Java platforms
|
data/README.md
CHANGED
@@ -187,6 +187,28 @@ MessagePack::DefaultFactory.register_type(0x03, MyClass3)
|
|
187
187
|
MessagePack.unpack(data_with_ext_typeid_03) #=> MyClass3 instance
|
188
188
|
```
|
189
189
|
|
190
|
+
Alternatively, extension types can call the packer or unpacker recursively to generate the extension data:
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
Point = Struct.new(:x, :y)
|
194
|
+
factory = MessagePack::Factory.new
|
195
|
+
factory.register_type(
|
196
|
+
0x01,
|
197
|
+
Point,
|
198
|
+
packer: ->(point, packer) {
|
199
|
+
packer.write(point.x)
|
200
|
+
packer.write(point.y)
|
201
|
+
},
|
202
|
+
unpacker: ->(unpacker) {
|
203
|
+
x = unpacker.read
|
204
|
+
y = unpacker.read
|
205
|
+
Point.new(x, y)
|
206
|
+
},
|
207
|
+
recursive: true,
|
208
|
+
)
|
209
|
+
factory.load(factory.dump(Point.new(12, 34))) # => #<struct Point x=12, y=34>
|
210
|
+
```
|
211
|
+
|
190
212
|
## Buffer API
|
191
213
|
|
192
214
|
MessagePack for Ruby provides a buffer API so that you can read or write data by hand, not via Packer or Unpacker API.
|
data/doclib/msgpack/factory.rb
CHANGED
@@ -31,7 +31,7 @@ module MessagePack
|
|
31
31
|
#
|
32
32
|
# See Packer#initialize for supported options.
|
33
33
|
#
|
34
|
-
def dump(obj, options=
|
34
|
+
def dump(obj, options=nil)
|
35
35
|
end
|
36
36
|
alias pack dump
|
37
37
|
|
@@ -57,13 +57,13 @@ module MessagePack
|
|
57
57
|
#
|
58
58
|
# See Unpacker#initialize for supported options.
|
59
59
|
#
|
60
|
-
def load(data, options=
|
60
|
+
def load(data, options=nil)
|
61
61
|
end
|
62
62
|
alias unpack load
|
63
63
|
|
64
64
|
#
|
65
65
|
# Register a type and Class to be registered for packer and/or unpacker.
|
66
|
-
# If options are not
|
66
|
+
# If options are not specified, factory will use :to_msgpack_ext for packer, and
|
67
67
|
# :from_msgpack_ext for unpacker.
|
68
68
|
#
|
69
69
|
# @param type [Fixnum] type id of registered Class (0-127)
|
@@ -76,6 +76,7 @@ module MessagePack
|
|
76
76
|
# * *:packer* specify symbol or proc object for packer
|
77
77
|
# * *:unpacker* specify symbol or proc object for unpacker
|
78
78
|
# * *:optimized_symbols_parsing* specify true to use the optimized symbols parsing (not supported on JRuby now)
|
79
|
+
# * *recursive* specify true to receive the packer or unpacker as argument to generate the extension body manually.
|
79
80
|
#
|
80
81
|
def register_type(type, klass, options={})
|
81
82
|
end
|
@@ -98,5 +99,47 @@ module MessagePack
|
|
98
99
|
#
|
99
100
|
def type_registered?(klass_or_type, selector=:both)
|
100
101
|
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Creates a MessagePack::PooledFactory instance of the given size.
|
105
|
+
#
|
106
|
+
# PooledFactory keeps Packer and Unpacker instance in a pool for improved performance.
|
107
|
+
# Note that the size defines how many instances are kept in cache, not the maximum of instances
|
108
|
+
# that can be created. If the pool limit is reached, a new instance is created anyway.
|
109
|
+
#
|
110
|
+
# @param size [Fixnum] specify how many Packer and Unpacker to keep in cache (default 1)
|
111
|
+
# @param options [Hash] Combined options for Packer and Unpacker. See Packer#initialize and Unpacker#initialize
|
112
|
+
# for supported options.
|
113
|
+
def pool(size=1, **options)
|
114
|
+
end
|
115
|
+
|
116
|
+
class Pool
|
117
|
+
#
|
118
|
+
# Deserializes an object from the string or io and returns it.
|
119
|
+
#
|
120
|
+
# If there're not enough data to deserialize one object, this method raises EOFError.
|
121
|
+
# If data format is invalid, this method raises MessagePack::MalformedFormatError.
|
122
|
+
# If the object nests too deeply, this method raises MessagePack::StackError.
|
123
|
+
#
|
124
|
+
# @param data [String]
|
125
|
+
# @return [Object] deserialized object
|
126
|
+
#
|
127
|
+
# See Unpacker#initialize for supported options.
|
128
|
+
#
|
129
|
+
def load(data)
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Serialize the passed value
|
134
|
+
#
|
135
|
+
# If it could not serialize the object, it raises
|
136
|
+
# NoMethodError: undefined method `to_msgpack' for #<the_object>.
|
137
|
+
#
|
138
|
+
# @param obj [Object] object to serialize
|
139
|
+
# @return [String] serialized object
|
140
|
+
#
|
141
|
+
def dump(object)
|
142
|
+
end
|
143
|
+
end
|
101
144
|
end
|
102
145
|
end
|
data/doclib/msgpack/packer.rb
CHANGED
@@ -14,7 +14,7 @@ module MessagePack
|
|
14
14
|
# @overload initialize(io, options={})
|
15
15
|
# @param io [IO]
|
16
16
|
# @param options [Hash]
|
17
|
-
# This packer writes
|
17
|
+
# This packer writes serialized objects into the IO when the internal buffer is filled.
|
18
18
|
# _io_ must respond to write(string) or append(string) method.
|
19
19
|
#
|
20
20
|
# Supported options:
|
@@ -33,12 +33,12 @@ module MessagePack
|
|
33
33
|
#
|
34
34
|
# @overload register_type(type, klass, &block)
|
35
35
|
# @param type [Fixnum] type id (0-127) user defined type id for specified Class
|
36
|
-
# @param klass [Class] Class to be serialized with
|
36
|
+
# @param klass [Class] Class to be serialized with specified type id
|
37
37
|
# @yieldparam object [Object] object to be serialized
|
38
38
|
#
|
39
39
|
# @overload register_type(type, klass, method_name)
|
40
40
|
# @param type [Fixnum] type id (0-127) user defined type id for specified Class
|
41
|
-
# @param klass [Class] Class to be serialized with
|
41
|
+
# @param klass [Class] Class to be serialized with specified type id
|
42
42
|
# @param method_name [Symbol] method which returns bytes of serialized representation
|
43
43
|
#
|
44
44
|
# @return nil
|
@@ -155,8 +155,9 @@ module MessagePack
|
|
155
155
|
#
|
156
156
|
# @return nil
|
157
157
|
#
|
158
|
-
def
|
158
|
+
def reset
|
159
159
|
end
|
160
|
+
alias clear reset
|
160
161
|
|
161
162
|
#
|
162
163
|
# Returns size of the internal buffer. Same as buffer.size.
|
data/doclib/msgpack/unpacker.rb
CHANGED
@@ -36,7 +36,7 @@ module MessagePack
|
|
36
36
|
#
|
37
37
|
# @overload register_type(type, klass, class_method_name)
|
38
38
|
# @param type [Fixnum] type id (0-127) user defined type id for specified Class
|
39
|
-
# @param klass [Class] Class to be serialized with
|
39
|
+
# @param klass [Class] Class to be serialized with specified type id
|
40
40
|
# @param class_method_name [Symbol] class method which returns an instance object
|
41
41
|
#
|
42
42
|
# @return nil
|
@@ -149,7 +149,7 @@ module MessagePack
|
|
149
149
|
#
|
150
150
|
# It repeats until the io or internal buffer does not include any complete objects.
|
151
151
|
#
|
152
|
-
# If
|
152
|
+
# If an IO is set, it repeats to read data from the IO when the buffer
|
153
153
|
# becomes empty until the IO raises EOFError.
|
154
154
|
#
|
155
155
|
# This method could raise same errors with _read_ excepting EOFError.
|
@@ -224,4 +224,10 @@ public class Buffer extends RubyObject {
|
|
224
224
|
public IRubyObject writeTo(ThreadContext ctx, IRubyObject io) {
|
225
225
|
return io.callMethod(ctx, "write", readCommon(ctx, null, false));
|
226
226
|
}
|
227
|
+
|
228
|
+
public ByteList getBytes() {
|
229
|
+
byte[] bytes = new byte[rawSize()];
|
230
|
+
buffer.get(bytes);
|
231
|
+
return new ByteList(bytes, binaryEncoding);
|
232
|
+
}
|
227
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,7 +36,7 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
35
36
|
private final RubyClass unexpectedTypeErrorClass;
|
36
37
|
private final RubyClass unknownExtTypeErrorClass;
|
37
38
|
|
38
|
-
private
|
39
|
+
private Unpacker unpacker;
|
39
40
|
private ByteBuffer buffer;
|
40
41
|
private boolean symbolizeKeys;
|
41
42
|
private boolean freeze;
|
@@ -45,29 +46,29 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
45
46
|
this(runtime, null, new byte[] {}, 0, 0, false, false, false);
|
46
47
|
}
|
47
48
|
|
48
|
-
public Decoder(Ruby runtime,
|
49
|
-
this(runtime,
|
49
|
+
public Decoder(Ruby runtime, Unpacker unpacker) {
|
50
|
+
this(runtime, unpacker, new byte[] {}, 0, 0, false, false, false);
|
50
51
|
}
|
51
52
|
|
52
53
|
public Decoder(Ruby runtime, byte[] bytes) {
|
53
54
|
this(runtime, null, bytes, 0, bytes.length, false, false, false);
|
54
55
|
}
|
55
56
|
|
56
|
-
public Decoder(Ruby runtime,
|
57
|
-
this(runtime,
|
57
|
+
public Decoder(Ruby runtime, Unpacker unpacker, byte[] bytes) {
|
58
|
+
this(runtime, unpacker, bytes, 0, bytes.length, false, false, false);
|
58
59
|
}
|
59
60
|
|
60
|
-
public Decoder(Ruby runtime,
|
61
|
-
this(runtime,
|
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);
|
62
63
|
}
|
63
64
|
|
64
|
-
public Decoder(Ruby runtime,
|
65
|
-
this(runtime,
|
65
|
+
public Decoder(Ruby runtime, Unpacker unpacker, byte[] bytes, int offset, int length) {
|
66
|
+
this(runtime, unpacker, bytes, offset, length, false, false, false);
|
66
67
|
}
|
67
68
|
|
68
|
-
public Decoder(Ruby runtime,
|
69
|
+
public Decoder(Ruby runtime, Unpacker unpacker, byte[] bytes, int offset, int length, boolean symbolizeKeys, boolean freeze, boolean allowUnknownExt) {
|
69
70
|
this.runtime = runtime;
|
70
|
-
this.
|
71
|
+
this.unpacker = unpacker;
|
71
72
|
this.symbolizeKeys = symbolizeKeys;
|
72
73
|
this.freeze = freeze;
|
73
74
|
this.allowUnknownExt = allowUnknownExt;
|
@@ -154,18 +155,21 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
154
155
|
|
155
156
|
private IRubyObject consumeExtension(int size) {
|
156
157
|
int type = buffer.get();
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
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
|
+
}
|
164
168
|
}
|
165
169
|
}
|
166
170
|
|
167
171
|
if (this.allowUnknownExt) {
|
168
|
-
return ExtensionValue.newExtensionValue(runtime, type,
|
172
|
+
return ExtensionValue.newExtensionValue(runtime, type, readBytes(size));
|
169
173
|
}
|
170
174
|
|
171
175
|
throw runtime.newRaiseException(unknownExtTypeErrorClass, "unexpected extension type");
|
@@ -38,12 +38,16 @@ public class Encoder {
|
|
38
38
|
private final Encoding utf8Encoding;
|
39
39
|
private final boolean compatibilityMode;
|
40
40
|
private final ExtensionRegistry registry;
|
41
|
+
private final Packer packer;
|
41
42
|
|
42
43
|
public boolean hasSymbolExtType;
|
44
|
+
private boolean hasBigintExtType;
|
45
|
+
private boolean recursiveExtension;
|
43
46
|
|
44
47
|
private ByteBuffer buffer;
|
45
48
|
|
46
|
-
public Encoder(Ruby runtime, boolean compatibilityMode, ExtensionRegistry registry, boolean hasSymbolExtType) {
|
49
|
+
public Encoder(Ruby runtime, Packer packer, boolean compatibilityMode, ExtensionRegistry registry, boolean hasSymbolExtType, boolean hasBigintExtType) {
|
50
|
+
this.packer = packer;
|
47
51
|
this.runtime = runtime;
|
48
52
|
this.buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE);
|
49
53
|
this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
|
@@ -51,6 +55,7 @@ public class Encoder {
|
|
51
55
|
this.compatibilityMode = compatibilityMode;
|
52
56
|
this.registry = registry;
|
53
57
|
this.hasSymbolExtType = hasSymbolExtType;
|
58
|
+
this.hasBigintExtType = hasBigintExtType;
|
54
59
|
}
|
55
60
|
|
56
61
|
public boolean isCompatibilityMode() {
|
@@ -66,9 +71,17 @@ public class Encoder {
|
|
66
71
|
}
|
67
72
|
|
68
73
|
private IRubyObject readRubyString() {
|
69
|
-
|
70
|
-
|
71
|
-
|
74
|
+
if (recursiveExtension) {
|
75
|
+
// If recursiveExtension is true, it means we re-entered encode, so we MUST NOT flush the buffer.
|
76
|
+
// Instead we return an empty string to act as a null object for the caller. The buffer will actually
|
77
|
+
// be flushed once we're done serializing the recursive extension.
|
78
|
+
// All other method that consume the buffer should do so through readRubyString or implement the same logic.
|
79
|
+
return runtime.newString();
|
80
|
+
} else {
|
81
|
+
IRubyObject str = runtime.newString(new ByteList(buffer.array(), 0, buffer.position(), binaryEncoding, false));
|
82
|
+
buffer.clear();
|
83
|
+
return str;
|
84
|
+
}
|
72
85
|
}
|
73
86
|
|
74
87
|
public IRubyObject encode(IRubyObject object) {
|
@@ -147,7 +160,10 @@ public class Encoder {
|
|
147
160
|
BigInteger value = object.getBigIntegerValue();
|
148
161
|
if (value.compareTo(RubyBignum.LONG_MIN) < 0 || value.compareTo(RubyBignum.LONG_MAX) > 0) {
|
149
162
|
if (value.bitLength() > 64 || (value.bitLength() > 63 && value.signum() < 0)) {
|
150
|
-
|
163
|
+
if (hasBigintExtType && tryAppendWithExtTypeLookup(object)) {
|
164
|
+
return;
|
165
|
+
}
|
166
|
+
throw runtime.newRangeError(String.format("Cannot pack big integer: %s", value));
|
151
167
|
}
|
152
168
|
ensureRemainingCapacity(9);
|
153
169
|
buffer.put(value.signum() < 0 ? INT64 : UINT64);
|
@@ -391,19 +407,31 @@ public class Encoder {
|
|
391
407
|
|
392
408
|
private boolean tryAppendWithExtTypeLookup(IRubyObject object) {
|
393
409
|
if (registry != null) {
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
410
|
+
ExtensionRegistry.ExtensionEntry entry = registry.lookupExtensionForObject(object);
|
411
|
+
if (entry != null) {
|
412
|
+
IRubyObject proc = entry.getPackerProc();
|
413
|
+
int type = entry.getTypeId();
|
414
|
+
|
415
|
+
if (entry.isRecursive()) {
|
416
|
+
ByteBuffer oldBuffer = buffer;
|
417
|
+
buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE);
|
418
|
+
boolean previousRecursiveExtension = recursiveExtension;
|
419
|
+
recursiveExtension = true;
|
420
|
+
|
421
|
+
ByteList payload;
|
422
|
+
try {
|
423
|
+
IRubyObject args[] = { object, packer };
|
424
|
+
proc.callMethod(runtime.getCurrentContext(), "call", args);
|
425
|
+
payload = new ByteList(buffer.array(), 0, buffer.position(), binaryEncoding, false);
|
426
|
+
} finally {
|
427
|
+
recursiveExtension = previousRecursiveExtension;
|
428
|
+
buffer = oldBuffer;
|
429
|
+
}
|
430
|
+
appendExt(type, payload);
|
431
|
+
} else {
|
432
|
+
RubyString bytes = proc.callMethod(runtime.getCurrentContext(), "call", object).asString();
|
433
|
+
appendExt(type, bytes.getByteList());
|
434
|
+
}
|
407
435
|
return true;
|
408
436
|
}
|
409
437
|
}
|
@@ -59,64 +59,46 @@ public class ExtensionRegistry {
|
|
59
59
|
return hash;
|
60
60
|
}
|
61
61
|
|
62
|
-
public void put(RubyModule mod, int typeId, IRubyObject packerProc, IRubyObject packerArg, IRubyObject unpackerProc, IRubyObject unpackerArg) {
|
63
|
-
ExtensionEntry entry = new ExtensionEntry(mod, typeId, packerProc, packerArg, unpackerProc, unpackerArg);
|
62
|
+
public void put(RubyModule mod, int typeId, boolean recursive, IRubyObject packerProc, IRubyObject packerArg, IRubyObject unpackerProc, IRubyObject unpackerArg) {
|
63
|
+
ExtensionEntry entry = new ExtensionEntry(mod, typeId, recursive, packerProc, packerArg, unpackerProc, unpackerArg);
|
64
64
|
extensionsByModule.put(mod, entry);
|
65
65
|
extensionsByTypeId[typeId + 128] = entry;
|
66
66
|
extensionsByAncestor.clear();
|
67
67
|
}
|
68
68
|
|
69
|
-
public
|
69
|
+
public ExtensionEntry lookupExtensionByTypeId(int typeId) {
|
70
70
|
ExtensionEntry e = extensionsByTypeId[typeId + 128];
|
71
71
|
if (e != null && e.hasUnpacker()) {
|
72
|
-
return e
|
73
|
-
} else {
|
74
|
-
return null;
|
72
|
+
return e;
|
75
73
|
}
|
74
|
+
return null;
|
76
75
|
}
|
77
76
|
|
78
|
-
public
|
77
|
+
public ExtensionEntry lookupExtensionForObject(IRubyObject object) {
|
79
78
|
RubyModule lookupClass = null;
|
80
|
-
|
79
|
+
ExtensionEntry entry = null;
|
81
80
|
/*
|
82
81
|
* Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
|
83
82
|
* String have no singleton class and raise a TypeError when trying to get
|
84
83
|
* it.
|
85
|
-
*
|
86
|
-
* Since all but symbols are already filtered out when reaching this code
|
87
|
-
* only symbols are checked here.
|
88
84
|
*/
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
return pair;
|
94
|
-
}
|
85
|
+
lookupClass = object.getMetaClass();
|
86
|
+
entry = extensionsByModule.get(lookupClass);
|
87
|
+
if (entry != null && entry.hasPacker()) {
|
88
|
+
return entry;
|
95
89
|
}
|
96
90
|
|
97
|
-
|
98
|
-
if (
|
99
|
-
|
91
|
+
RubyModule realClass = object.getType();
|
92
|
+
if (realClass != lookupClass) {
|
93
|
+
entry = extensionsByModule.get(realClass);
|
94
|
+
if (entry != null && entry.hasPacker()) {
|
95
|
+
return entry;
|
96
|
+
}
|
100
97
|
}
|
101
98
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
ExtensionEntry e = findEntryByModuleOrAncestor(lookupClass);
|
106
|
-
if (e != null && e.hasPacker()) {
|
107
|
-
extensionsByAncestor.put(e.getExtensionModule(), e);
|
108
|
-
return e.toPackerProcTypeIdPair(lookupClass.getRuntime().getCurrentContext());
|
109
|
-
}
|
110
|
-
return null;
|
111
|
-
}
|
112
|
-
|
113
|
-
private IRubyObject[] fetchEntryByModule(final RubyModule mod) {
|
114
|
-
ExtensionEntry e = extensionsByModule.get(mod);
|
115
|
-
if (e == null) {
|
116
|
-
e = extensionsByAncestor.get(mod);
|
117
|
-
}
|
118
|
-
if (e != null && e.hasPacker()) {
|
119
|
-
return e.toPackerProcTypeIdPair(mod.getRuntime().getCurrentContext());
|
99
|
+
entry = findEntryByModuleOrAncestor(lookupClass);
|
100
|
+
if (entry != null && entry.hasPacker()) {
|
101
|
+
return entry;
|
120
102
|
}
|
121
103
|
return null;
|
122
104
|
}
|
@@ -132,17 +114,19 @@ public class ExtensionRegistry {
|
|
132
114
|
return null;
|
133
115
|
}
|
134
116
|
|
135
|
-
|
117
|
+
public static class ExtensionEntry {
|
136
118
|
private final RubyModule mod;
|
137
119
|
private final int typeId;
|
120
|
+
private final boolean recursive;
|
138
121
|
private final IRubyObject packerProc;
|
139
122
|
private final IRubyObject packerArg;
|
140
123
|
private final IRubyObject unpackerProc;
|
141
124
|
private final IRubyObject unpackerArg;
|
142
125
|
|
143
|
-
public ExtensionEntry(RubyModule mod, int typeId, IRubyObject packerProc, IRubyObject packerArg, IRubyObject unpackerProc, IRubyObject unpackerArg) {
|
126
|
+
public ExtensionEntry(RubyModule mod, int typeId, boolean recursive, IRubyObject packerProc, IRubyObject packerArg, IRubyObject unpackerProc, IRubyObject unpackerArg) {
|
144
127
|
this.mod = mod;
|
145
128
|
this.typeId = typeId;
|
129
|
+
this.recursive = recursive;
|
146
130
|
this.packerProc = packerProc;
|
147
131
|
this.packerArg = packerArg;
|
148
132
|
this.unpackerProc = unpackerProc;
|
@@ -157,6 +141,10 @@ public class ExtensionRegistry {
|
|
157
141
|
return typeId;
|
158
142
|
}
|
159
143
|
|
144
|
+
public boolean isRecursive() {
|
145
|
+
return recursive;
|
146
|
+
}
|
147
|
+
|
160
148
|
public boolean hasPacker() {
|
161
149
|
return packerProc != null;
|
162
150
|
}
|
@@ -12,6 +12,8 @@ import org.jruby.RubyInteger;
|
|
12
12
|
import org.jruby.RubyFixnum;
|
13
13
|
import org.jruby.RubyString;
|
14
14
|
import org.jruby.RubySymbol;
|
15
|
+
import org.jruby.RubyProc;
|
16
|
+
import org.jruby.RubyMethod;
|
15
17
|
import org.jruby.runtime.builtin.IRubyObject;
|
16
18
|
import org.jruby.anno.JRubyClass;
|
17
19
|
import org.jruby.anno.JRubyMethod;
|
@@ -25,14 +27,16 @@ import static org.jruby.runtime.Visibility.PRIVATE;
|
|
25
27
|
public class Factory extends RubyObject {
|
26
28
|
private static final long serialVersionUID = 8441284623445322492L;
|
27
29
|
private final Ruby runtime;
|
28
|
-
private
|
30
|
+
private ExtensionRegistry extensionRegistry;
|
29
31
|
private boolean hasSymbolExtType;
|
32
|
+
private boolean hasBigIntExtType;
|
30
33
|
|
31
34
|
public Factory(Ruby runtime, RubyClass type) {
|
32
35
|
super(runtime, type);
|
33
36
|
this.runtime = runtime;
|
34
37
|
this.extensionRegistry = new ExtensionRegistry();
|
35
38
|
this.hasSymbolExtType = false;
|
39
|
+
this.hasBigIntExtType = false;
|
36
40
|
}
|
37
41
|
|
38
42
|
static class FactoryAllocator implements ObjectAllocator {
|
@@ -50,9 +54,17 @@ public class Factory extends RubyObject {
|
|
50
54
|
return this;
|
51
55
|
}
|
52
56
|
|
53
|
-
@JRubyMethod(name = "
|
57
|
+
@JRubyMethod(name = "dup")
|
58
|
+
public IRubyObject dup() {
|
59
|
+
Factory clone = (Factory)super.dup();
|
60
|
+
clone.extensionRegistry = extensionRegistry();
|
61
|
+
clone.hasSymbolExtType = hasSymbolExtType;
|
62
|
+
return clone;
|
63
|
+
}
|
64
|
+
|
65
|
+
@JRubyMethod(name = "packer", optional = 2)
|
54
66
|
public Packer packer(ThreadContext ctx, IRubyObject[] args) {
|
55
|
-
return Packer.newPacker(ctx, extensionRegistry(), hasSymbolExtType, args);
|
67
|
+
return Packer.newPacker(ctx, extensionRegistry(), hasSymbolExtType, hasBigIntExtType, args);
|
56
68
|
}
|
57
69
|
|
58
70
|
@JRubyMethod(name = "unpacker", optional = 2)
|
@@ -77,6 +89,8 @@ public class Factory extends RubyObject {
|
|
77
89
|
IRubyObject packerArg;
|
78
90
|
IRubyObject unpackerArg;
|
79
91
|
|
92
|
+
RubyHash options = null;
|
93
|
+
|
80
94
|
if (isFrozen()) {
|
81
95
|
throw runtime.newRuntimeError("can't modify frozen Factory");
|
82
96
|
}
|
@@ -86,7 +100,7 @@ public class Factory extends RubyObject {
|
|
86
100
|
unpackerArg = runtime.newSymbol("from_msgpack_ext");
|
87
101
|
} else if (args.length == 3) {
|
88
102
|
if (args[args.length - 1] instanceof RubyHash) {
|
89
|
-
|
103
|
+
options = (RubyHash) args[args.length - 1];
|
90
104
|
packerArg = options.fastARef(runtime.newSymbol("packer"));
|
91
105
|
unpackerArg = options.fastARef(runtime.newSymbol("unpacker"));
|
92
106
|
IRubyObject optimizedSymbolsParsingArg = options.fastARef(runtime.newSymbol("optimized_symbols_parsing"));
|
@@ -118,17 +132,38 @@ public class Factory extends RubyObject {
|
|
118
132
|
if (unpackerArg != null) {
|
119
133
|
if (unpackerArg instanceof RubyString || unpackerArg instanceof RubySymbol) {
|
120
134
|
unpackerProc = extModule.method(unpackerArg.callMethod(ctx, "to_sym"));
|
135
|
+
} else if (unpackerArg instanceof RubyProc || unpackerArg instanceof RubyMethod) {
|
136
|
+
unpackerProc = unpackerArg;
|
121
137
|
} else {
|
122
138
|
unpackerProc = unpackerArg.callMethod(ctx, "method", runtime.newSymbol("call"));
|
123
139
|
}
|
124
140
|
}
|
125
141
|
|
126
|
-
|
142
|
+
boolean recursive = false;
|
143
|
+
if (options != null) {
|
144
|
+
IRubyObject recursiveExtensionArg = options.fastARef(runtime.newSymbol("recursive"));
|
145
|
+
if (recursiveExtensionArg != null && recursiveExtensionArg.isTrue()) {
|
146
|
+
recursive = true;
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
extensionRegistry.put(extModule, (int) typeId, recursive, packerProc, packerArg, unpackerProc, unpackerArg);
|
127
151
|
|
128
152
|
if (extModule == runtime.getSymbol()) {
|
129
153
|
hasSymbolExtType = true;
|
130
154
|
}
|
131
155
|
|
156
|
+
if (options != null) {
|
157
|
+
IRubyObject oversizedIntegerExtensionArg = options.fastARef(runtime.newSymbol("oversized_integer_extension"));
|
158
|
+
if (oversizedIntegerExtensionArg != null && oversizedIntegerExtensionArg.isTrue()) {
|
159
|
+
if (extModule == runtime.getModule("Integer")) {
|
160
|
+
hasBigIntExtType = true;
|
161
|
+
} else {
|
162
|
+
throw runtime.newArgumentError("oversized_integer_extension: true is only for Integer class");
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
132
167
|
return runtime.getNil();
|
133
168
|
}
|
134
169
|
}
|