msgpack 1.4.5 → 1.5.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 +4 -4
- data/.github/workflows/ci.yaml +5 -5
- data/ChangeLog +14 -0
- data/README.md +22 -0
- data/doclib/msgpack/factory.rb +45 -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 +24 -31
- 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_class.c +12 -3
- data/ext/msgpack/factory_class.c +62 -5
- data/ext/msgpack/packer.c +42 -5
- data/ext/msgpack/packer.h +24 -0
- data/ext/msgpack/packer_class.c +22 -19
- data/ext/msgpack/packer_ext_registry.c +13 -4
- data/ext/msgpack/packer_ext_registry.h +10 -5
- data/ext/msgpack/unpacker.c +59 -19
- data/ext/msgpack/unpacker_class.c +14 -5
- data/ext/msgpack/unpacker_ext_registry.c +3 -2
- data/ext/msgpack/unpacker_ext_registry.h +5 -2
- data/lib/msgpack/bigint.rb +69 -0
- data/lib/msgpack/factory.rb +103 -0
- 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 +220 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/timestamp_spec.rb +2 -2
- 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: 7de0658b1f87162270c3cc2aac70ffff8d408d974faac6ff5ad009fa11dba4dd
|
4
|
+
data.tar.gz: 9da35f2cc47ced45efd96b10ad8a3b491f0658b5ba247ad7b4aa22b901c66110
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b23c683b4c7fbbedd8dedc5d6eb8f5d6778aa3d3f7afef839cfe3227fc2edff713d9f17d6c8ce3808a6103325d7923ca6abfaf8792dba11485ed9d067fe6aa42
|
7
|
+
data.tar.gz: ced82946481b00d99a69aea792efbeb93982d39836bc763c7c4a0f71844ca48044cff1f58c9695aa4ebb19d0be6a0b43f2e3b4af04ca06d7ad4bfc798cacd0b8
|
data/.github/workflows/ci.yaml
CHANGED
@@ -25,12 +25,12 @@ jobs:
|
|
25
25
|
bundler-cache: true # 'bundle install' and cache
|
26
26
|
- run: bundle exec rake
|
27
27
|
|
28
|
-
|
28
|
+
other:
|
29
29
|
strategy:
|
30
30
|
fail-fast: false
|
31
31
|
matrix:
|
32
32
|
os: [ubuntu]
|
33
|
-
ruby: ['jruby-9.2.19.0', 'jruby-9.3.3.0']
|
33
|
+
ruby: ['jruby-9.2.19.0', 'jruby-9.3.3.0', 'truffleruby']
|
34
34
|
runs-on: ${{ matrix.os }}-latest
|
35
35
|
steps:
|
36
36
|
- uses: actions/checkout@v2
|
@@ -38,7 +38,7 @@ jobs:
|
|
38
38
|
with:
|
39
39
|
ruby-version: ${{ matrix.ruby }}
|
40
40
|
bundler-cache: true # 'bundle install' and cache
|
41
|
-
- run: bundle exec rake
|
41
|
+
- run: bundle exec rake spec
|
42
42
|
|
43
43
|
head-versions:
|
44
44
|
continue-on-error: true
|
@@ -46,7 +46,7 @@ jobs:
|
|
46
46
|
fail-fast: false
|
47
47
|
matrix:
|
48
48
|
os: [ubuntu]
|
49
|
-
ruby: ['ruby-head', 'jruby-head'
|
49
|
+
ruby: ['ruby-head', 'jruby-head']
|
50
50
|
runs-on: ${{ matrix.os }}-latest
|
51
51
|
steps:
|
52
52
|
- uses: actions/checkout@v2
|
@@ -54,4 +54,4 @@ jobs:
|
|
54
54
|
with:
|
55
55
|
ruby-version: ${{ matrix.ruby }}
|
56
56
|
bundler-cache: true # 'bundle install' and cache
|
57
|
-
- run: bundle exec rake || echo "failed, but ignore it"
|
57
|
+
- run: bundle exec rake spec || echo "failed, but ignore it"
|
data/ChangeLog
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
2022-05-27 version 1.5.2:
|
2
|
+
|
3
|
+
* Fix bug about unpacking ext type objects with the recursive option
|
4
|
+
|
5
|
+
2022-04-07 version 1.5.1:
|
6
|
+
|
7
|
+
* Fix bug about packing/unpacking ext type objects with the recursive option
|
8
|
+
|
9
|
+
2022-04-06 version 1.5.0:
|
10
|
+
|
11
|
+
* Add recursive option on Factory#register_type to operate Packer/Unpacker manually
|
12
|
+
* Add oversized_integer_extension option on Factory#register_type to pack/unpack bigint using ext types
|
13
|
+
* Add Factory#pool method and Factory::Pool class to provide pooled Packer and Unpacker instances
|
14
|
+
|
1
15
|
2022-02-15 version 1.4.5:
|
2
16
|
|
3
17
|
* Fix to create UTF-8 Symbol keys when symbolize_keys: true
|
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,7 +57,7 @@ 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
|
|
@@ -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
|
@@ -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,59 +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
84
|
*/
|
86
85
|
lookupClass = object.getMetaClass();
|
87
|
-
|
88
|
-
if (
|
89
|
-
return
|
86
|
+
entry = extensionsByModule.get(lookupClass);
|
87
|
+
if (entry != null && entry.hasPacker()) {
|
88
|
+
return entry;
|
90
89
|
}
|
91
90
|
|
92
91
|
RubyModule realClass = object.getType();
|
93
92
|
if (realClass != lookupClass) {
|
94
|
-
|
95
|
-
if (
|
96
|
-
return
|
93
|
+
entry = extensionsByModule.get(realClass);
|
94
|
+
if (entry != null && entry.hasPacker()) {
|
95
|
+
return entry;
|
97
96
|
}
|
98
97
|
}
|
99
98
|
|
100
|
-
|
101
|
-
if (
|
102
|
-
|
103
|
-
return e.toPackerProcTypeIdPair(lookupClass.getRuntime().getCurrentContext());
|
104
|
-
}
|
105
|
-
return null;
|
106
|
-
}
|
107
|
-
|
108
|
-
private IRubyObject[] fetchEntryByModule(final RubyModule mod) {
|
109
|
-
ExtensionEntry e = extensionsByModule.get(mod);
|
110
|
-
if (e == null) {
|
111
|
-
e = extensionsByAncestor.get(mod);
|
112
|
-
}
|
113
|
-
if (e != null && e.hasPacker()) {
|
114
|
-
return e.toPackerProcTypeIdPair(mod.getRuntime().getCurrentContext());
|
99
|
+
entry = findEntryByModuleOrAncestor(lookupClass);
|
100
|
+
if (entry != null && entry.hasPacker()) {
|
101
|
+
return entry;
|
115
102
|
}
|
116
103
|
return null;
|
117
104
|
}
|
@@ -127,17 +114,19 @@ public class ExtensionRegistry {
|
|
127
114
|
return null;
|
128
115
|
}
|
129
116
|
|
130
|
-
|
117
|
+
public static class ExtensionEntry {
|
131
118
|
private final RubyModule mod;
|
132
119
|
private final int typeId;
|
120
|
+
private final boolean recursive;
|
133
121
|
private final IRubyObject packerProc;
|
134
122
|
private final IRubyObject packerArg;
|
135
123
|
private final IRubyObject unpackerProc;
|
136
124
|
private final IRubyObject unpackerArg;
|
137
125
|
|
138
|
-
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) {
|
139
127
|
this.mod = mod;
|
140
128
|
this.typeId = typeId;
|
129
|
+
this.recursive = recursive;
|
141
130
|
this.packerProc = packerProc;
|
142
131
|
this.packerArg = packerArg;
|
143
132
|
this.unpackerProc = unpackerProc;
|
@@ -152,6 +141,10 @@ public class ExtensionRegistry {
|
|
152
141
|
return typeId;
|
153
142
|
}
|
154
143
|
|
144
|
+
public boolean isRecursive() {
|
145
|
+
return recursive;
|
146
|
+
}
|
147
|
+
|
155
148
|
public boolean hasPacker() {
|
156
149
|
return packerProc != null;
|
157
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
|
}
|
@@ -32,17 +32,19 @@ public class Packer extends RubyObject {
|
|
32
32
|
private Buffer buffer;
|
33
33
|
private Encoder encoder;
|
34
34
|
private boolean hasSymbolExtType;
|
35
|
+
private boolean hasBigintExtType;
|
35
36
|
private Encoding binaryEncoding;
|
36
37
|
|
37
|
-
public Packer(Ruby runtime, RubyClass type, ExtensionRegistry registry, boolean hasSymbolExtType) {
|
38
|
+
public Packer(Ruby runtime, RubyClass type, ExtensionRegistry registry, boolean hasSymbolExtType, boolean hasBigintExtType) {
|
38
39
|
super(runtime, type);
|
39
40
|
this.registry = registry;
|
40
41
|
this.hasSymbolExtType = hasSymbolExtType;
|
42
|
+
this.hasBigintExtType = hasBigintExtType;
|
41
43
|
}
|
42
44
|
|
43
45
|
static class PackerAllocator implements ObjectAllocator {
|
44
46
|
public IRubyObject allocate(Ruby runtime, RubyClass type) {
|
45
|
-
return new Packer(runtime, type, null, false);
|
47
|
+
return new Packer(runtime, type, null, false, false);
|
46
48
|
}
|
47
49
|
}
|
48
50
|
|
@@ -50,25 +52,33 @@ public class Packer extends RubyObject {
|
|
50
52
|
public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
|
51
53
|
boolean compatibilityMode = false;
|
52
54
|
Ruby runtime = ctx.runtime;
|
53
|
-
if (args.length > 0
|
54
|
-
RubyHash options =
|
55
|
-
|
56
|
-
|
55
|
+
if (args.length > 0) {
|
56
|
+
RubyHash options = null;
|
57
|
+
if (args[args.length - 1] instanceof RubyHash) {
|
58
|
+
options = (RubyHash) args[args.length - 1];
|
59
|
+
} else if (args.length > 1 && args[args.length - 2] instanceof RubyHash) {
|
60
|
+
options = (RubyHash) args[args.length - 2];
|
61
|
+
}
|
62
|
+
|
63
|
+
if (options != null) {
|
64
|
+
IRubyObject mode = options.fastARef(runtime.newSymbol("compatibility_mode"));
|
65
|
+
compatibilityMode = (mode != null) && mode.isTrue();
|
66
|
+
}
|
57
67
|
}
|
58
68
|
if (registry == null) {
|
59
69
|
// registry is null when allocate -> initialize
|
60
70
|
// registry is already initialized (and somthing might be registered) when newPacker from Factory
|
61
71
|
this.registry = new ExtensionRegistry();
|
62
72
|
}
|
63
|
-
this.encoder = new Encoder(runtime, compatibilityMode, registry, hasSymbolExtType);
|
73
|
+
this.encoder = new Encoder(runtime, this, compatibilityMode, registry, hasSymbolExtType, hasBigintExtType);
|
64
74
|
this.buffer = new Buffer(runtime, runtime.getModule("MessagePack").getClass("Buffer"));
|
65
75
|
this.buffer.initialize(ctx, args);
|
66
76
|
this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
|
67
77
|
return this;
|
68
78
|
}
|
69
79
|
|
70
|
-
public static Packer newPacker(ThreadContext ctx, ExtensionRegistry extRegistry, boolean hasSymbolExtType, IRubyObject[] args) {
|
71
|
-
Packer packer = new Packer(ctx.runtime, ctx.runtime.getModule("MessagePack").getClass("Packer"), extRegistry, hasSymbolExtType);
|
80
|
+
public static Packer newPacker(ThreadContext ctx, ExtensionRegistry extRegistry, boolean hasSymbolExtType, boolean hasBigintExtType, IRubyObject[] args) {
|
81
|
+
Packer packer = new Packer(ctx.runtime, ctx.runtime.getModule("MessagePack").getClass("Packer"), extRegistry, hasSymbolExtType, hasBigintExtType);
|
72
82
|
packer.initialize(ctx, args);
|
73
83
|
return packer;
|
74
84
|
}
|
@@ -114,7 +124,7 @@ public class Packer extends RubyObject {
|
|
114
124
|
}
|
115
125
|
RubyModule extModule = (RubyModule) mod;
|
116
126
|
|
117
|
-
registry.put(extModule, (int) typeId, proc, arg, null, null);
|
127
|
+
registry.put(extModule, (int) typeId, false, proc, arg, null, null);
|
118
128
|
|
119
129
|
if (extModule == runtime.getSymbol()) {
|
120
130
|
encoder.hasSymbolExtType = true;
|
@@ -257,7 +267,7 @@ public class Packer extends RubyObject {
|
|
257
267
|
return buffer.size(ctx);
|
258
268
|
}
|
259
269
|
|
260
|
-
@JRubyMethod(name = "clear")
|
270
|
+
@JRubyMethod(name = "clear", alias = { "reset" })
|
261
271
|
public IRubyObject clear(ThreadContext ctx) {
|
262
272
|
return buffer.clear(ctx);
|
263
273
|
}
|