msgpack 0.7.0dev1-x86-mingw32 → 0.7.0-x86-mingw32
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/.gitignore +1 -0
- data/.travis.yml +2 -0
- data/ChangeLog +8 -0
- data/README.rdoc +36 -2
- data/ext/java/org/msgpack/jruby/Decoder.java +55 -16
- data/ext/java/org/msgpack/jruby/Encoder.java +31 -8
- data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +159 -0
- data/ext/java/org/msgpack/jruby/Factory.java +117 -0
- data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +23 -6
- data/ext/java/org/msgpack/jruby/Packer.java +65 -6
- data/ext/java/org/msgpack/jruby/Unpacker.java +104 -22
- data/ext/msgpack/packer_class.c +7 -0
- data/ext/msgpack/packer_ext_registry.c +0 -8
- data/ext/msgpack/packer_ext_registry.h +0 -3
- data/ext/msgpack/unpacker_class.c +14 -0
- data/ext/msgpack/unpacker_ext_registry.c +0 -6
- data/ext/msgpack/unpacker_ext_registry.h +0 -3
- data/lib/msgpack/version.rb +1 -1
- data/msgpack.gemspec +5 -3
- data/spec/cruby/unpacker_spec.rb +0 -247
- data/spec/factory_spec.rb +0 -3
- data/spec/jruby/{msgpack/unpacker_spec.rb → unpacker_spec.rb} +30 -159
- data/spec/msgpack_spec.rb +1 -1
- data/spec/packer_spec.rb +135 -4
- data/spec/unpacker_spec.rb +465 -6
- metadata +9 -6
- data/spec/cruby/packer_spec.rb +0 -138
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d0e3d42a5abee5ed3099e8784636b4bcbf10731
|
4
|
+
data.tar.gz: f40232648f4ec2efa26b3874ebe3de519a2196e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a162332df41c000debc176cdd0d9cce9a67da29d2a20d3e7d9704d3726e541abf89be49517d36e9a4e8c9f6100bd811f793d1ba97e44f8de645bd4f1db50c497
|
7
|
+
data.tar.gz: 9cebb8ccc7f423f20c9784e01718e8ec098a7e3f00f4379ad208e3efddd71b48e275cd137f965e72b74f33067a5d730b3a191429eae4a1288da7cbb83250396f
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/ChangeLog
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
2015-10-24 version 0.7.0:
|
2
|
+
|
3
|
+
* Add extention types support.
|
4
|
+
* Fix to share almost all test cases between CRuby and JRuby implementations.
|
5
|
+
* Fixed JRuby implementation to raise UnknownExtTypeError for unregistered ext type ids
|
6
|
+
instead to generate MessagePack::ExtensionValue instances.
|
7
|
+
(Specify `allow_unknown_ext: true` as unpacker option for v0.6.x behavior.)
|
8
|
+
|
1
9
|
2015-07-22 version 0.6.2:
|
2
10
|
|
3
11
|
* Fix release workflow: Ruby 2.1 and 2.2 are supported for Windows (2.0 is omitted)
|
data/README.rdoc
CHANGED
@@ -36,7 +36,6 @@ or build msgpack-ruby and install:
|
|
36
36
|
* Exchange objects between software components written in different languages
|
37
37
|
* You'll need a flexible but efficient format so that components exchange objects while keeping compatibility
|
38
38
|
|
39
|
-
|
40
39
|
= Portability
|
41
40
|
|
42
41
|
MessagePack for Ruby should run on x86, ARM, PowerPC, SPARC and other CPU architectures.
|
@@ -92,6 +91,32 @@ or event-driven style which works well with EventMachine:
|
|
92
91
|
|
93
92
|
See {API reference}[http://ruby.msgpack.org/MessagePack/Unpacker.html] for details.
|
94
93
|
|
94
|
+
= Extension Types
|
95
|
+
|
96
|
+
Packer and Unpacker support {Extension types of MessagePack}[https://github.com/msgpack/msgpack/blob/master/spec.md#types-extension-type].
|
97
|
+
|
98
|
+
# register how to serialize custom class at first
|
99
|
+
pk = MessagePack::Packer.new(io)
|
100
|
+
pk.register_type(0x01, MyClass1, :to_msgpack_ext) # equal to pk.register_type(0x01, MyClass)
|
101
|
+
pk.register_type(0x02, MyClass2){|obj| obj.how_to_serialize() } # blocks also available
|
102
|
+
|
103
|
+
# almost same API for unpacker
|
104
|
+
uk = MessagePack::Unpacker.new()
|
105
|
+
uk.register_type(0x01, MyClass1, :from_msgpack_ext)
|
106
|
+
uk.register_type(0x02){|data| MyClass2.create_from_serialized_data(data) }
|
107
|
+
|
108
|
+
MessagePack::Factory is to create packer and unpacker which have same extention types.
|
109
|
+
|
110
|
+
factory = MessagePack::Factory.new
|
111
|
+
factory.register_type(0x01, MyClass1) # same with next line
|
112
|
+
factory.register_type(0x01, MyClass1, packer: :to_msgpack_ext, unpacker: :from_msgpack_ext)
|
113
|
+
pk = factory.packer(options_for_packer)
|
114
|
+
uk = factory.unpacker(options_for_unpacker)
|
115
|
+
|
116
|
+
For *MessagePack.pack* and *MessagePack.unpack*, default packer/unpacker refer *MessagePack::DefaultFactory*. Call *MessagePack::DefaultFactory.register_type* to enable types process globally.
|
117
|
+
|
118
|
+
MessagePack::DefaultFactory.register_type(0x03, MyClass3)
|
119
|
+
MessagePack.unpack(data_with_ext_typeid_03) #=> MyClass3 instance
|
95
120
|
|
96
121
|
= Buffer API
|
97
122
|
|
@@ -129,9 +154,18 @@ MessagePack mingw32/64 rubygems build process uses {rake-compiler-dock}[https://
|
|
129
154
|
|
130
155
|
Once this step successes, target gems exist in pkg/msgpack-*-{x86,x64}-mingw32.gem.
|
131
156
|
|
157
|
+
== Updating documents
|
158
|
+
|
159
|
+
Online documents (http://ruby.msgpack.org) is generated from gh-pages branch.
|
160
|
+
Following commands update documents in gh-pages branch:
|
161
|
+
|
162
|
+
bundle exec rake doc
|
163
|
+
git checkout gh-pages
|
164
|
+
cp doc/* ./ -a
|
165
|
+
|
132
166
|
= Copyright
|
133
167
|
|
134
168
|
Author:: Sadayuki Furuhashi <frsyuki@gmail.com>
|
135
|
-
Copyright:: Copyright (c) 2008-
|
169
|
+
Copyright:: Copyright (c) 2008-2015 Sadayuki Furuhashi
|
136
170
|
License:: Apache License, Version 2.0
|
137
171
|
|
@@ -12,6 +12,7 @@ import org.jruby.RubyObject;
|
|
12
12
|
import org.jruby.RubyClass;
|
13
13
|
import org.jruby.RubyBignum;
|
14
14
|
import org.jruby.RubyString;
|
15
|
+
import org.jruby.RubyArray;
|
15
16
|
import org.jruby.RubyHash;
|
16
17
|
import org.jruby.exceptions.RaiseException;
|
17
18
|
import org.jruby.runtime.builtin.IRubyObject;
|
@@ -29,33 +30,58 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
29
30
|
private final Encoding utf8Encoding;
|
30
31
|
private final RubyClass unpackErrorClass;
|
31
32
|
private final RubyClass underflowErrorClass;
|
33
|
+
private final RubyClass malformedFormatErrorClass;
|
34
|
+
private final RubyClass stackErrorClass;
|
32
35
|
private final RubyClass unexpectedTypeErrorClass;
|
36
|
+
private final RubyClass unknownExtTypeErrorClass;
|
33
37
|
|
38
|
+
private ExtensionRegistry registry;
|
34
39
|
private ByteBuffer buffer;
|
35
40
|
private boolean symbolizeKeys;
|
41
|
+
private boolean allowUnknownExt;
|
36
42
|
|
37
43
|
public Decoder(Ruby runtime) {
|
38
|
-
this(runtime, new byte[] {}, 0, 0);
|
44
|
+
this(runtime, null, new byte[] {}, 0, 0, false, false);
|
45
|
+
}
|
46
|
+
|
47
|
+
public Decoder(Ruby runtime, ExtensionRegistry registry) {
|
48
|
+
this(runtime, registry, new byte[] {}, 0, 0, false, false);
|
39
49
|
}
|
40
50
|
|
41
51
|
public Decoder(Ruby runtime, byte[] bytes) {
|
42
|
-
this(runtime, bytes, 0, bytes.length);
|
52
|
+
this(runtime, null, bytes, 0, bytes.length, false, false);
|
53
|
+
}
|
54
|
+
|
55
|
+
public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes) {
|
56
|
+
this(runtime, registry, bytes, 0, bytes.length, false, false);
|
57
|
+
}
|
58
|
+
|
59
|
+
public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, boolean symbolizeKeys, boolean allowUnknownExt) {
|
60
|
+
this(runtime, registry, bytes, 0, bytes.length, symbolizeKeys, allowUnknownExt);
|
61
|
+
}
|
62
|
+
|
63
|
+
public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length) {
|
64
|
+
this(runtime, registry, bytes, offset, length, false, false);
|
43
65
|
}
|
44
66
|
|
45
|
-
public Decoder(Ruby runtime, byte[] bytes, int offset, int length) {
|
67
|
+
public Decoder(Ruby runtime, ExtensionRegistry registry, byte[] bytes, int offset, int length, boolean symbolizeKeys, boolean allowUnknownExt) {
|
46
68
|
this.runtime = runtime;
|
69
|
+
this.registry = registry;
|
70
|
+
this.symbolizeKeys = symbolizeKeys;
|
71
|
+
this.allowUnknownExt = allowUnknownExt;
|
47
72
|
this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
|
48
73
|
this.utf8Encoding = UTF8Encoding.INSTANCE;
|
49
74
|
this.unpackErrorClass = runtime.getModule("MessagePack").getClass("UnpackError");
|
50
75
|
this.underflowErrorClass = runtime.getModule("MessagePack").getClass("UnderflowError");
|
76
|
+
this.malformedFormatErrorClass = runtime.getModule("MessagePack").getClass("MalformedFormatError");
|
77
|
+
this.stackErrorClass = runtime.getModule("MessagePack").getClass("StackError");
|
51
78
|
this.unexpectedTypeErrorClass = runtime.getModule("MessagePack").getClass("UnexpectedTypeError");
|
79
|
+
this.unknownExtTypeErrorClass = runtime.getModule("MessagePack").getClass("UnknownExtTypeError");
|
80
|
+
this.symbolizeKeys = symbolizeKeys;
|
81
|
+
this.allowUnknownExt = allowUnknownExt;
|
52
82
|
feed(bytes, offset, length);
|
53
83
|
}
|
54
84
|
|
55
|
-
public void symbolizeKeys(boolean symbolize) {
|
56
|
-
this.symbolizeKeys = symbolize;
|
57
|
-
}
|
58
|
-
|
59
85
|
public void feed(byte[] bytes) {
|
60
86
|
feed(bytes, 0, bytes.length);
|
61
87
|
}
|
@@ -73,7 +99,7 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
73
99
|
}
|
74
100
|
|
75
101
|
public void reset() {
|
76
|
-
buffer
|
102
|
+
buffer = null;
|
77
103
|
}
|
78
104
|
|
79
105
|
public int offset() {
|
@@ -118,7 +144,20 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
118
144
|
private IRubyObject consumeExtension(int size) {
|
119
145
|
int type = buffer.get();
|
120
146
|
byte[] payload = readBytes(size);
|
121
|
-
|
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));
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
if (this.allowUnknownExt) {
|
157
|
+
return ExtensionValue.newExtensionValue(runtime, type, payload);
|
158
|
+
}
|
159
|
+
|
160
|
+
throw runtime.newRaiseException(unknownExtTypeErrorClass, "unexpected extension type");
|
122
161
|
}
|
123
162
|
|
124
163
|
private byte[] readBytes(int size) {
|
@@ -142,11 +181,11 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
142
181
|
try {
|
143
182
|
byte b = buffer.get();
|
144
183
|
if ((b & 0xf0) == 0x90) {
|
145
|
-
|
184
|
+
return runtime.newFixnum(b & 0x0f);
|
146
185
|
} else if (b == ARY16) {
|
147
|
-
|
186
|
+
return runtime.newFixnum(buffer.getShort() & 0xffff);
|
148
187
|
} else if (b == ARY32) {
|
149
|
-
|
188
|
+
return runtime.newFixnum(buffer.getInt());
|
150
189
|
}
|
151
190
|
throw runtime.newRaiseException(unexpectedTypeErrorClass, "unexpected type");
|
152
191
|
} catch (RaiseException re) {
|
@@ -163,11 +202,11 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
163
202
|
try {
|
164
203
|
byte b = buffer.get();
|
165
204
|
if ((b & 0xf0) == 0x80) {
|
166
|
-
|
205
|
+
return runtime.newFixnum(b & 0x0f);
|
167
206
|
} else if (b == MAP16) {
|
168
|
-
|
207
|
+
return runtime.newFixnum(buffer.getShort() & 0xffff);
|
169
208
|
} else if (b == MAP32) {
|
170
|
-
|
209
|
+
return runtime.newFixnum(buffer.getInt());
|
171
210
|
}
|
172
211
|
throw runtime.newRaiseException(unexpectedTypeErrorClass, "unexpected type");
|
173
212
|
} catch (RaiseException re) {
|
@@ -233,7 +272,7 @@ public class Decoder implements Iterator<IRubyObject> {
|
|
233
272
|
default: return runtime.newFixnum(b);
|
234
273
|
}
|
235
274
|
buffer.position(position);
|
236
|
-
throw runtime.newRaiseException(
|
275
|
+
throw runtime.newRaiseException(malformedFormatErrorClass, "Illegal byte sequence");
|
237
276
|
} catch (RaiseException re) {
|
238
277
|
buffer.position(position);
|
239
278
|
throw re;
|
@@ -34,15 +34,21 @@ public class Encoder {
|
|
34
34
|
private final Encoding binaryEncoding;
|
35
35
|
private final Encoding utf8Encoding;
|
36
36
|
private final boolean compatibilityMode;
|
37
|
+
private final ExtensionRegistry registry;
|
37
38
|
|
38
39
|
private ByteBuffer buffer;
|
39
40
|
|
40
|
-
public Encoder(Ruby runtime, boolean compatibilityMode) {
|
41
|
+
public Encoder(Ruby runtime, boolean compatibilityMode, ExtensionRegistry registry) {
|
41
42
|
this.runtime = runtime;
|
42
43
|
this.buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE);
|
43
44
|
this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
|
44
45
|
this.utf8Encoding = UTF8Encoding.INSTANCE;
|
45
46
|
this.compatibilityMode = compatibilityMode;
|
47
|
+
this.registry = registry;
|
48
|
+
}
|
49
|
+
|
50
|
+
public boolean isCompatibilityMode() {
|
51
|
+
return compatibilityMode;
|
46
52
|
}
|
47
53
|
|
48
54
|
private void ensureRemainingCapacity(int c) {
|
@@ -107,7 +113,7 @@ public class Encoder {
|
|
107
113
|
} else if (object instanceof ExtensionValue) {
|
108
114
|
appendExtensionValue((ExtensionValue) object);
|
109
115
|
} else {
|
110
|
-
|
116
|
+
appendOther(object, destination);
|
111
117
|
}
|
112
118
|
}
|
113
119
|
|
@@ -295,12 +301,7 @@ public class Encoder {
|
|
295
301
|
}
|
296
302
|
}
|
297
303
|
|
298
|
-
private void
|
299
|
-
long type = ((RubyFixnum)object.get_type()).getLongValue();
|
300
|
-
if (type < -128 || type > 127) {
|
301
|
-
throw object.getRuntime().newRangeError(String.format("integer %d too big to convert to `signed char'", type));
|
302
|
-
}
|
303
|
-
ByteList payloadBytes = ((RubyString)object.payload()).getByteList();
|
304
|
+
private void appendExt(int type, ByteList payloadBytes) {
|
304
305
|
int payloadSize = payloadBytes.length();
|
305
306
|
int outputSize = 0;
|
306
307
|
boolean fixSize = payloadSize == 1 || payloadSize == 2 || payloadSize == 4 || payloadSize == 8 || payloadSize == 16;
|
@@ -338,6 +339,28 @@ public class Encoder {
|
|
338
339
|
buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), payloadSize);
|
339
340
|
}
|
340
341
|
|
342
|
+
private void appendExtensionValue(ExtensionValue object) {
|
343
|
+
long type = ((RubyFixnum)object.get_type()).getLongValue();
|
344
|
+
if (type < -128 || type > 127) {
|
345
|
+
throw object.getRuntime().newRangeError(String.format("integer %d too big to convert to `signed char'", type));
|
346
|
+
}
|
347
|
+
ByteList payloadBytes = ((RubyString)object.payload()).getByteList();
|
348
|
+
appendExt((int) type, payloadBytes);
|
349
|
+
}
|
350
|
+
|
351
|
+
private void appendOther(IRubyObject object, IRubyObject destination) {
|
352
|
+
if (registry != null) {
|
353
|
+
IRubyObject[] pair = registry.lookupPackerByClass(object.getType());
|
354
|
+
if (pair != null) {
|
355
|
+
RubyString bytes = pair[0].callMethod(runtime.getCurrentContext(), "call", object).asString();
|
356
|
+
int type = (int) ((RubyFixnum) pair[1]).getLongValue();
|
357
|
+
appendExt(type, bytes.getByteList());
|
358
|
+
return;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
appendCustom(object, destination);
|
362
|
+
}
|
363
|
+
|
341
364
|
private void appendCustom(IRubyObject object, IRubyObject destination) {
|
342
365
|
if (destination == null) {
|
343
366
|
IRubyObject result = object.callMethod(runtime.getCurrentContext(), "to_msgpack");
|
@@ -0,0 +1,159 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.RubyHash;
|
5
|
+
import org.jruby.RubyArray;
|
6
|
+
import org.jruby.RubyClass;
|
7
|
+
import org.jruby.RubyFixnum;
|
8
|
+
import org.jruby.runtime.ThreadContext;
|
9
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
10
|
+
|
11
|
+
import java.util.Map;
|
12
|
+
import java.util.HashMap;
|
13
|
+
|
14
|
+
public class ExtensionRegistry {
|
15
|
+
private final Map<RubyClass, ExtensionEntry> extensionsByClass;
|
16
|
+
private final Map<RubyClass, ExtensionEntry> extensionsByAncestor;
|
17
|
+
private final ExtensionEntry[] extensionsByTypeId;
|
18
|
+
|
19
|
+
public ExtensionRegistry() {
|
20
|
+
this(new HashMap<RubyClass, ExtensionEntry>());
|
21
|
+
}
|
22
|
+
|
23
|
+
private ExtensionRegistry(Map<RubyClass, ExtensionEntry> extensionsByClass) {
|
24
|
+
this.extensionsByClass = new HashMap<RubyClass, ExtensionEntry>(extensionsByClass);
|
25
|
+
this.extensionsByAncestor = new HashMap<RubyClass, ExtensionEntry>();
|
26
|
+
this.extensionsByTypeId = new ExtensionEntry[256];
|
27
|
+
for (ExtensionEntry entry : extensionsByClass.values()) {
|
28
|
+
if (entry.hasUnpacker()) {
|
29
|
+
extensionsByTypeId[entry.getTypeId() + 128] = entry;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
public ExtensionRegistry dup() {
|
35
|
+
return new ExtensionRegistry(extensionsByClass);
|
36
|
+
}
|
37
|
+
|
38
|
+
public IRubyObject toInternalPackerRegistry(ThreadContext ctx) {
|
39
|
+
RubyHash hash = RubyHash.newHash(ctx.getRuntime());
|
40
|
+
for (RubyClass extensionClass : extensionsByClass.keySet()) {
|
41
|
+
ExtensionEntry entry = extensionsByClass.get(extensionClass);
|
42
|
+
if (entry.hasPacker()) {
|
43
|
+
hash.put(extensionClass, entry.toPackerTuple(ctx));
|
44
|
+
}
|
45
|
+
}
|
46
|
+
return hash;
|
47
|
+
}
|
48
|
+
|
49
|
+
public IRubyObject toInternalUnpackerRegistry(ThreadContext ctx) {
|
50
|
+
RubyHash hash = RubyHash.newHash(ctx.getRuntime());
|
51
|
+
for (int typeIdIndex = 0 ; typeIdIndex < 256 ; typeIdIndex++) {
|
52
|
+
ExtensionEntry entry = extensionsByTypeId[typeIdIndex];
|
53
|
+
if (entry != null && entry.hasUnpacker()) {
|
54
|
+
IRubyObject typeId = RubyFixnum.newFixnum(ctx.getRuntime(), typeIdIndex - 128);
|
55
|
+
hash.put(typeId, entry.toUnpackerTuple(ctx));
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return hash;
|
59
|
+
}
|
60
|
+
|
61
|
+
public void put(RubyClass cls, int typeId, IRubyObject packerProc, IRubyObject packerArg, IRubyObject unpackerProc, IRubyObject unpackerArg) {
|
62
|
+
ExtensionEntry entry = new ExtensionEntry(cls, typeId, packerProc, packerArg, unpackerProc, unpackerArg);
|
63
|
+
extensionsByClass.put(cls, entry);
|
64
|
+
extensionsByTypeId[typeId + 128] = entry;
|
65
|
+
extensionsByAncestor.clear();
|
66
|
+
}
|
67
|
+
|
68
|
+
public IRubyObject lookupUnpackerByTypeId(int typeId) {
|
69
|
+
ExtensionEntry e = extensionsByTypeId[typeId + 128];
|
70
|
+
if (e != null && e.hasUnpacker()) {
|
71
|
+
return e.getUnpackerProc();
|
72
|
+
} else {
|
73
|
+
return null;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
public IRubyObject[] lookupPackerByClass(RubyClass cls) {
|
78
|
+
ExtensionEntry e = extensionsByClass.get(cls);
|
79
|
+
if (e == null) {
|
80
|
+
e = extensionsByAncestor.get(cls);
|
81
|
+
}
|
82
|
+
if (e == null) {
|
83
|
+
e = findEntryByClassOrAncestor(cls);
|
84
|
+
if (e != null) {
|
85
|
+
extensionsByAncestor.put(e.getExtensionClass(), e);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
if (e != null && e.hasPacker()) {
|
89
|
+
return e.toPackerProcTypeIdPair(cls.getRuntime().getCurrentContext());
|
90
|
+
} else {
|
91
|
+
return null;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
private ExtensionEntry findEntryByClassOrAncestor(final RubyClass cls) {
|
96
|
+
ThreadContext ctx = cls.getRuntime().getCurrentContext();
|
97
|
+
for (RubyClass extensionClass : extensionsByClass.keySet()) {
|
98
|
+
RubyArray ancestors = (RubyArray) cls.callMethod(ctx, "ancestors");
|
99
|
+
if (ancestors.callMethod(ctx, "include?", extensionClass).isTrue()) {
|
100
|
+
return extensionsByClass.get(extensionClass);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
return null;
|
104
|
+
}
|
105
|
+
|
106
|
+
private static class ExtensionEntry {
|
107
|
+
private final RubyClass cls;
|
108
|
+
private final int typeId;
|
109
|
+
private final IRubyObject packerProc;
|
110
|
+
private final IRubyObject packerArg;
|
111
|
+
private final IRubyObject unpackerProc;
|
112
|
+
private final IRubyObject unpackerArg;
|
113
|
+
|
114
|
+
public ExtensionEntry(RubyClass cls, int typeId, IRubyObject packerProc, IRubyObject packerArg, IRubyObject unpackerProc, IRubyObject unpackerArg) {
|
115
|
+
this.cls = cls;
|
116
|
+
this.typeId = typeId;
|
117
|
+
this.packerProc = packerProc;
|
118
|
+
this.packerArg = packerArg;
|
119
|
+
this.unpackerProc = unpackerProc;
|
120
|
+
this.unpackerArg = unpackerArg;
|
121
|
+
}
|
122
|
+
|
123
|
+
public RubyClass getExtensionClass() {
|
124
|
+
return cls;
|
125
|
+
}
|
126
|
+
|
127
|
+
public int getTypeId() {
|
128
|
+
return typeId;
|
129
|
+
}
|
130
|
+
|
131
|
+
public boolean hasPacker() {
|
132
|
+
return packerProc != null;
|
133
|
+
}
|
134
|
+
|
135
|
+
public boolean hasUnpacker() {
|
136
|
+
return unpackerProc != null;
|
137
|
+
}
|
138
|
+
|
139
|
+
public IRubyObject getPackerProc() {
|
140
|
+
return packerProc;
|
141
|
+
}
|
142
|
+
|
143
|
+
public IRubyObject getUnpackerProc() {
|
144
|
+
return unpackerProc;
|
145
|
+
}
|
146
|
+
|
147
|
+
public RubyArray toPackerTuple(ThreadContext ctx) {
|
148
|
+
return RubyArray.newArray(ctx.getRuntime(), new IRubyObject[] {RubyFixnum.newFixnum(ctx.getRuntime(), typeId), packerProc, packerArg});
|
149
|
+
}
|
150
|
+
|
151
|
+
public RubyArray toUnpackerTuple(ThreadContext ctx) {
|
152
|
+
return RubyArray.newArray(ctx.getRuntime(), new IRubyObject[] {cls, unpackerProc, unpackerArg});
|
153
|
+
}
|
154
|
+
|
155
|
+
public IRubyObject[] toPackerProcTypeIdPair(ThreadContext ctx) {
|
156
|
+
return new IRubyObject[] {packerProc, RubyFixnum.newFixnum(ctx.getRuntime(), typeId)};
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|