msgpack 0.7.0dev1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +10 -8
- 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: 08b929d16e3f5eb48b0de6a10041092be2510361
|
4
|
+
data.tar.gz: 34c606ea1c703c22f94d1295b5648f4430fd69ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ec69a5b4e904359b7c1d1a15f37ee2e57fa5e340fbab0e658cf2d476d736d41100cd350ce580f52afbbb88721640be3bd120583adfd6f179aa1b3afa4395142
|
7
|
+
data.tar.gz: 63bf4dd13deaa7c767bbc1f6c50170548cb6819ebb2ca87282939f6cd88da078820af2453634dcb0e4c3d056073807f34ac86623c5b75ec89ea416ed8fa6f7c1
|
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
|
+
}
|