msgpack 0.5.9-x86-mingw32 → 0.5.10-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -2
- data/.travis.yml +2 -3
- data/ChangeLog +6 -0
- data/Rakefile +5 -1
- data/ext/java/org/msgpack/jruby/Buffer.java +221 -0
- data/ext/java/org/msgpack/jruby/Decoder.java +201 -0
- data/ext/java/org/msgpack/jruby/Encoder.java +309 -0
- data/ext/java/org/msgpack/jruby/ExtensionValue.java +136 -0
- data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +113 -0
- data/ext/java/org/msgpack/jruby/Packer.java +78 -0
- data/ext/java/org/msgpack/jruby/Types.java +37 -0
- data/ext/java/org/msgpack/jruby/Unpacker.java +170 -0
- data/lib/msgpack.rb +11 -4
- data/lib/msgpack/version.rb +1 -1
- data/msgpack.gemspec +11 -6
- data/spec/{packer_spec.rb → cruby/packer_spec.rb} +0 -0
- data/spec/{unpacker_spec.rb → cruby/unpacker_spec.rb} +0 -0
- data/spec/format_spec.rb +32 -30
- data/spec/jruby/benchmarks/shootout_bm.rb +73 -0
- data/spec/jruby/benchmarks/symbolize_keys_bm.rb +25 -0
- data/spec/jruby/msgpack/unpacker_spec.rb +290 -0
- data/spec/jruby/msgpack_spec.rb +136 -0
- data/spec/pack_spec.rb +67 -0
- data/spec/spec_helper.rb +10 -4
- data/spec/unpack_spec.rb +72 -0
- metadata +22 -5
@@ -0,0 +1,309 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
import java.math.BigInteger;
|
5
|
+
import java.nio.ByteBuffer;
|
6
|
+
|
7
|
+
import org.jruby.Ruby;
|
8
|
+
import org.jruby.RubyObject;
|
9
|
+
import org.jruby.RubyNil;
|
10
|
+
import org.jruby.RubyBoolean;
|
11
|
+
import org.jruby.RubyBignum;
|
12
|
+
import org.jruby.RubyInteger;
|
13
|
+
import org.jruby.RubyFixnum;
|
14
|
+
import org.jruby.RubyFloat;
|
15
|
+
import org.jruby.RubyString;
|
16
|
+
import org.jruby.RubySymbol;
|
17
|
+
import org.jruby.RubyArray;
|
18
|
+
import org.jruby.RubyHash;
|
19
|
+
import org.jruby.RubyEncoding;
|
20
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
21
|
+
import org.jruby.util.ByteList;
|
22
|
+
|
23
|
+
import org.jcodings.Encoding;
|
24
|
+
import org.jcodings.specific.UTF8Encoding;
|
25
|
+
|
26
|
+
import static org.msgpack.jruby.Types.*;
|
27
|
+
|
28
|
+
|
29
|
+
public class Encoder {
|
30
|
+
|
31
|
+
private static final int CACHE_LINE_SIZE = 64;
|
32
|
+
private static final int ARRAY_HEADER_SIZE = 24;
|
33
|
+
|
34
|
+
private final Ruby runtime;
|
35
|
+
private final Encoding binaryEncoding;
|
36
|
+
private final Encoding utf8Encoding;
|
37
|
+
|
38
|
+
private ByteBuffer buffer;
|
39
|
+
|
40
|
+
public Encoder(Ruby runtime) {
|
41
|
+
this.runtime = runtime;
|
42
|
+
this.buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE);
|
43
|
+
this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
|
44
|
+
this.utf8Encoding = UTF8Encoding.INSTANCE;
|
45
|
+
}
|
46
|
+
|
47
|
+
private void ensureRemainingCapacity(int c) {
|
48
|
+
if (buffer.remaining() < c) {
|
49
|
+
int newLength = Math.max(buffer.capacity() + (buffer.capacity() >> 1), buffer.capacity() + c);
|
50
|
+
newLength += CACHE_LINE_SIZE - ((ARRAY_HEADER_SIZE + newLength) % CACHE_LINE_SIZE);
|
51
|
+
buffer = ByteBuffer.allocate(newLength).put(buffer.array(), 0, buffer.position());
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
private IRubyObject readRubyString() {
|
56
|
+
IRubyObject str = runtime.newString(new ByteList(buffer.array(), 0, buffer.position(), binaryEncoding, false));
|
57
|
+
buffer.clear();
|
58
|
+
return str;
|
59
|
+
}
|
60
|
+
|
61
|
+
public IRubyObject encode(IRubyObject object) {
|
62
|
+
appendObject(object);
|
63
|
+
return readRubyString();
|
64
|
+
}
|
65
|
+
|
66
|
+
public IRubyObject encode(IRubyObject object, IRubyObject destination) {
|
67
|
+
appendObject(object, destination);
|
68
|
+
return readRubyString();
|
69
|
+
}
|
70
|
+
|
71
|
+
public IRubyObject encodeArrayHeader(int size) {
|
72
|
+
appendArrayHeader(size);
|
73
|
+
return readRubyString();
|
74
|
+
}
|
75
|
+
|
76
|
+
public IRubyObject encodeMapHeader(int size) {
|
77
|
+
appendHashHeader(size);
|
78
|
+
return readRubyString();
|
79
|
+
}
|
80
|
+
|
81
|
+
private void appendObject(IRubyObject object) {
|
82
|
+
appendObject(object, null);
|
83
|
+
}
|
84
|
+
|
85
|
+
private void appendObject(IRubyObject object, IRubyObject destination) {
|
86
|
+
if (object == null || object instanceof RubyNil) {
|
87
|
+
ensureRemainingCapacity(1);
|
88
|
+
buffer.put(NIL);
|
89
|
+
} else if (object instanceof RubyBoolean) {
|
90
|
+
ensureRemainingCapacity(1);
|
91
|
+
buffer.put(((RubyBoolean) object).isTrue() ? TRUE : FALSE);
|
92
|
+
} else if (object instanceof RubyBignum) {
|
93
|
+
appendBignum((RubyBignum) object);
|
94
|
+
} else if (object instanceof RubyInteger) {
|
95
|
+
appendInteger((RubyInteger) object);
|
96
|
+
} else if (object instanceof RubyFloat) {
|
97
|
+
appendFloat((RubyFloat) object);
|
98
|
+
} else if (object instanceof RubyString) {
|
99
|
+
appendString((RubyString) object);
|
100
|
+
} else if (object instanceof RubySymbol) {
|
101
|
+
appendString(((RubySymbol) object).asString());
|
102
|
+
} else if (object instanceof RubyArray) {
|
103
|
+
appendArray((RubyArray) object);
|
104
|
+
} else if (object instanceof RubyHash) {
|
105
|
+
appendHash((RubyHash) object);
|
106
|
+
} else if (object.respondsTo("to_msgpack")) {
|
107
|
+
appendCustom(object, destination);
|
108
|
+
} else {
|
109
|
+
throw runtime.newArgumentError(String.format("Cannot pack type: %s", object.getClass().getName()));
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
private void appendBignum(RubyBignum object) {
|
114
|
+
BigInteger value = ((RubyBignum) object).getBigIntegerValue();
|
115
|
+
if (value.bitLength() > 64 || (value.bitLength() > 63 && value.signum() < 0)) {
|
116
|
+
throw runtime.newArgumentError(String.format("Cannot pack big integer: %s", value));
|
117
|
+
}
|
118
|
+
ensureRemainingCapacity(9);
|
119
|
+
buffer.put(value.signum() < 0 ? INT64 : UINT64);
|
120
|
+
byte[] b = value.toByteArray();
|
121
|
+
buffer.put(b, b.length - 8, 8);
|
122
|
+
}
|
123
|
+
|
124
|
+
private void appendInteger(RubyInteger object) {
|
125
|
+
long value = ((RubyInteger) object).getLongValue();
|
126
|
+
if (value < 0) {
|
127
|
+
if (value < Short.MIN_VALUE) {
|
128
|
+
if (value < Integer.MIN_VALUE) {
|
129
|
+
ensureRemainingCapacity(9);
|
130
|
+
buffer.put(INT64);
|
131
|
+
buffer.putLong(value);
|
132
|
+
} else {
|
133
|
+
ensureRemainingCapacity(5);
|
134
|
+
buffer.put(INT32);
|
135
|
+
buffer.putInt((int) value);
|
136
|
+
}
|
137
|
+
} else if (value >= -0x20L) {
|
138
|
+
ensureRemainingCapacity(1);
|
139
|
+
byte b = (byte) (value | 0xe0);
|
140
|
+
buffer.put(b);
|
141
|
+
} else if (value < Byte.MIN_VALUE) {
|
142
|
+
ensureRemainingCapacity(3);
|
143
|
+
buffer.put(INT16);
|
144
|
+
buffer.putShort((short) value);
|
145
|
+
} else {
|
146
|
+
ensureRemainingCapacity(2);
|
147
|
+
buffer.put(INT8);
|
148
|
+
buffer.put((byte) value);
|
149
|
+
}
|
150
|
+
} else {
|
151
|
+
if (value < 0x10000L) {
|
152
|
+
if (value < 128L) {
|
153
|
+
ensureRemainingCapacity(1);
|
154
|
+
buffer.put((byte) value);
|
155
|
+
} else if (value < 0x100L) {
|
156
|
+
ensureRemainingCapacity(2);
|
157
|
+
buffer.put(UINT8);
|
158
|
+
buffer.put((byte) value);
|
159
|
+
} else {
|
160
|
+
ensureRemainingCapacity(3);
|
161
|
+
buffer.put(UINT16);
|
162
|
+
buffer.putShort((short) value);
|
163
|
+
}
|
164
|
+
} else if (value < 0x100000000L) {
|
165
|
+
ensureRemainingCapacity(5);
|
166
|
+
buffer.put(UINT32);
|
167
|
+
buffer.putInt((int) value);
|
168
|
+
} else {
|
169
|
+
ensureRemainingCapacity(9);
|
170
|
+
buffer.put(INT64);
|
171
|
+
buffer.putLong(value);
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
private void appendFloat(RubyFloat object) {
|
177
|
+
double value = object.getDoubleValue();
|
178
|
+
float f = (float) value;
|
179
|
+
//TODO: msgpack-ruby original does encode this value as Double, not float
|
180
|
+
// if (Double.compare(f, value) == 0) {
|
181
|
+
// ensureRemainingCapacity(5);
|
182
|
+
// buffer.put(FLOAT32);
|
183
|
+
// buffer.putFloat(f);
|
184
|
+
// } else {
|
185
|
+
ensureRemainingCapacity(9);
|
186
|
+
buffer.put(FLOAT64);
|
187
|
+
buffer.putDouble(value);
|
188
|
+
// }
|
189
|
+
}
|
190
|
+
|
191
|
+
private void appendString(RubyString object) {
|
192
|
+
Encoding encoding = object.getEncoding();
|
193
|
+
boolean binary = encoding == binaryEncoding;
|
194
|
+
if (encoding != utf8Encoding && encoding != binaryEncoding) {
|
195
|
+
object = (RubyString) ((RubyString) object).encode(runtime.getCurrentContext(), RubyEncoding.newEncoding(runtime, utf8Encoding));
|
196
|
+
}
|
197
|
+
ByteList bytes = object.getByteList();
|
198
|
+
int length = bytes.length();
|
199
|
+
if (length < 32 && !binary) {
|
200
|
+
ensureRemainingCapacity(1 + length);
|
201
|
+
buffer.put((byte) (length | FIXSTR));
|
202
|
+
//TODO: msgpack-ruby original does encode this value as RAW16 (currently should be BIN8/STR8)
|
203
|
+
// } else if (length <= 0xff) {
|
204
|
+
// ensureRemainingCapacity(2 + length);
|
205
|
+
// buffer.put(binary ? BIN8 : STR8);
|
206
|
+
// buffer.put((byte) length);
|
207
|
+
} else if (length <= 0xffff) {
|
208
|
+
ensureRemainingCapacity(3 + length);
|
209
|
+
buffer.put(binary ? BIN16 : STR16);
|
210
|
+
buffer.putShort((short) length);
|
211
|
+
} else {
|
212
|
+
ensureRemainingCapacity(5 + length);
|
213
|
+
buffer.put(binary ? BIN32 : STR32);
|
214
|
+
buffer.putInt((int) length);
|
215
|
+
}
|
216
|
+
buffer.put(bytes.unsafeBytes(), bytes.begin(), length);
|
217
|
+
}
|
218
|
+
|
219
|
+
private void appendArray(RubyArray object) {
|
220
|
+
appendArrayHeader(object);
|
221
|
+
appendArrayElements(object);
|
222
|
+
}
|
223
|
+
|
224
|
+
private void appendArrayHeader(RubyArray object) {
|
225
|
+
appendArrayHeader(object.size());
|
226
|
+
}
|
227
|
+
|
228
|
+
private void appendArrayHeader(int size) {
|
229
|
+
if (size < 16) {
|
230
|
+
ensureRemainingCapacity(1);
|
231
|
+
buffer.put((byte) (size | 0x90));
|
232
|
+
} else if (size < 0x10000) {
|
233
|
+
ensureRemainingCapacity(3);
|
234
|
+
buffer.put(ARY16);
|
235
|
+
buffer.putShort((short) size);
|
236
|
+
} else {
|
237
|
+
ensureRemainingCapacity(5);
|
238
|
+
buffer.put(ARY32);
|
239
|
+
buffer.putInt(size);
|
240
|
+
}
|
241
|
+
}
|
242
|
+
|
243
|
+
private void appendArrayElements(RubyArray object) {
|
244
|
+
int size = object.size();
|
245
|
+
for (int i = 0; i < size; i++) {
|
246
|
+
appendObject(object.eltOk(i));
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
private void appendHash(RubyHash object) {
|
251
|
+
appendHashHeader(object);
|
252
|
+
appendHashElements(object);
|
253
|
+
}
|
254
|
+
|
255
|
+
private void appendHashHeader(RubyHash object) {
|
256
|
+
appendHashHeader(object.size());
|
257
|
+
}
|
258
|
+
|
259
|
+
private void appendHashHeader(int size) {
|
260
|
+
if (size < 16) {
|
261
|
+
ensureRemainingCapacity(1);
|
262
|
+
buffer.put((byte) (size | 0x80));
|
263
|
+
} else if (size < 0x10000) {
|
264
|
+
ensureRemainingCapacity(3);
|
265
|
+
buffer.put(MAP16);
|
266
|
+
buffer.putShort((short) size);
|
267
|
+
} else {
|
268
|
+
ensureRemainingCapacity(5);
|
269
|
+
buffer.put(MAP32);
|
270
|
+
buffer.putInt(size);
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
private void appendHashElements(RubyHash object) {
|
275
|
+
int size = object.size();
|
276
|
+
HashVisitor visitor = new HashVisitor(size);
|
277
|
+
object.visitAll(visitor);
|
278
|
+
if (visitor.remain != 0) {
|
279
|
+
object.getRuntime().newConcurrencyError("Hash size changed while packing");
|
280
|
+
}
|
281
|
+
}
|
282
|
+
|
283
|
+
private class HashVisitor extends RubyHash.Visitor {
|
284
|
+
public int remain;
|
285
|
+
|
286
|
+
public HashVisitor(int size) {
|
287
|
+
remain = size;
|
288
|
+
}
|
289
|
+
|
290
|
+
public void visit(IRubyObject key, IRubyObject value) {
|
291
|
+
if (remain-- > 0) {
|
292
|
+
appendObject(key);
|
293
|
+
appendObject(value);
|
294
|
+
}
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
private void appendCustom(IRubyObject object, IRubyObject destination) {
|
299
|
+
if (destination == null) {
|
300
|
+
IRubyObject result = object.callMethod(runtime.getCurrentContext(), "to_msgpack");
|
301
|
+
ByteList bytes = result.asString().getByteList();
|
302
|
+
int length = bytes.length();
|
303
|
+
ensureRemainingCapacity(length);
|
304
|
+
buffer.put(bytes.unsafeBytes(), bytes.begin(), length);
|
305
|
+
} else {
|
306
|
+
object.callMethod(runtime.getCurrentContext(), "to_msgpack", destination);
|
307
|
+
}
|
308
|
+
}
|
309
|
+
}
|
@@ -0,0 +1,136 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
import java.util.Arrays;
|
5
|
+
import java.nio.ByteBuffer;
|
6
|
+
|
7
|
+
import org.jruby.Ruby;
|
8
|
+
import org.jruby.RubyClass;
|
9
|
+
import org.jruby.RubyObject;
|
10
|
+
import org.jruby.RubyFixnum;
|
11
|
+
import org.jruby.RubyString;
|
12
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
13
|
+
import org.jruby.runtime.ObjectAllocator;
|
14
|
+
import org.jruby.runtime.ThreadContext;
|
15
|
+
import org.jruby.anno.JRubyClass;
|
16
|
+
import org.jruby.anno.JRubyMethod;
|
17
|
+
import org.jruby.util.ByteList;
|
18
|
+
|
19
|
+
import static org.jruby.runtime.Visibility.PRIVATE;
|
20
|
+
|
21
|
+
import org.jcodings.Encoding;
|
22
|
+
|
23
|
+
import static org.msgpack.jruby.Types.*;
|
24
|
+
|
25
|
+
|
26
|
+
@JRubyClass(name="MessagePack::ExtensionValue")
|
27
|
+
public class ExtensionValue extends RubyObject {
|
28
|
+
private final Encoding binaryEncoding;
|
29
|
+
|
30
|
+
private RubyFixnum type;
|
31
|
+
private RubyString payload;
|
32
|
+
|
33
|
+
public ExtensionValue(Ruby runtime, RubyClass type) {
|
34
|
+
super(runtime, type);
|
35
|
+
this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
|
36
|
+
}
|
37
|
+
|
38
|
+
public static class ExtensionValueAllocator implements ObjectAllocator {
|
39
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
40
|
+
return new ExtensionValue(runtime, klass);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
public static ExtensionValue newExtensionValue(Ruby runtime, int type, byte[] payload) {
|
45
|
+
ExtensionValue v = new ExtensionValue(runtime, runtime.getModule("MessagePack").getClass("ExtensionValue"));
|
46
|
+
ByteList byteList = new ByteList(payload, runtime.getEncodingService().getAscii8bitEncoding());
|
47
|
+
v.initialize(runtime.getCurrentContext(), runtime.newFixnum(type), runtime.newString(byteList));
|
48
|
+
return v;
|
49
|
+
}
|
50
|
+
|
51
|
+
@JRubyMethod(name = "initialize", required = 2, visibility = PRIVATE)
|
52
|
+
public IRubyObject initialize(ThreadContext ctx, IRubyObject type, IRubyObject payload) {
|
53
|
+
this.type = (RubyFixnum) type;
|
54
|
+
this.payload = (RubyString) payload;
|
55
|
+
return this;
|
56
|
+
}
|
57
|
+
|
58
|
+
@JRubyMethod(name = "to_msgpack")
|
59
|
+
public IRubyObject toMsgpack() {
|
60
|
+
ByteList payloadBytes = payload.getByteList();
|
61
|
+
int payloadSize = payloadBytes.length();
|
62
|
+
int outputSize = 0;
|
63
|
+
boolean fixSize = payloadSize == 1 || payloadSize == 2 || payloadSize == 4 || payloadSize == 8 || payloadSize == 16;
|
64
|
+
if (fixSize) {
|
65
|
+
outputSize = 2 + payloadSize;
|
66
|
+
} else if (payloadSize < 0x100) {
|
67
|
+
outputSize = 3 + payloadSize;
|
68
|
+
} else if (payloadSize < 0x10000) {
|
69
|
+
outputSize = 4 + payloadSize;
|
70
|
+
} else {
|
71
|
+
outputSize = 6 + payloadSize;
|
72
|
+
}
|
73
|
+
byte[] bytes = new byte[outputSize];
|
74
|
+
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
75
|
+
if (payloadSize == 1) {
|
76
|
+
buffer.put(FIXEXT1);
|
77
|
+
buffer.put((byte) type.getLongValue());
|
78
|
+
buffer.put((byte) payloadBytes.get(0));
|
79
|
+
} else if (payloadSize == 2) {
|
80
|
+
buffer.put(FIXEXT2);
|
81
|
+
buffer.put((byte) type.getLongValue());
|
82
|
+
buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), 2);
|
83
|
+
} else if (payloadSize == 4) {
|
84
|
+
buffer.put(FIXEXT4);
|
85
|
+
buffer.put((byte) type.getLongValue());
|
86
|
+
buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), 4);
|
87
|
+
} else if (payloadSize == 8) {
|
88
|
+
buffer.put(FIXEXT8);
|
89
|
+
buffer.put((byte) type.getLongValue());
|
90
|
+
buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), 8);
|
91
|
+
} else if (payloadSize == 16) {
|
92
|
+
buffer.put(FIXEXT16);
|
93
|
+
buffer.put((byte) type.getLongValue());
|
94
|
+
buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), 16);
|
95
|
+
} else if (payloadSize < 0x100) {
|
96
|
+
buffer.put(VAREXT8);
|
97
|
+
buffer.put((byte) payloadSize);
|
98
|
+
buffer.put((byte) type.getLongValue());
|
99
|
+
buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), payloadSize);
|
100
|
+
} else if (payloadSize < 0x10000) {
|
101
|
+
buffer.put(VAREXT16);
|
102
|
+
buffer.putShort((short) payloadSize);
|
103
|
+
buffer.put((byte) type.getLongValue());
|
104
|
+
buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), payloadSize);
|
105
|
+
} else {
|
106
|
+
buffer.put(VAREXT32);
|
107
|
+
buffer.putInt(payloadSize);
|
108
|
+
buffer.put((byte) type.getLongValue());
|
109
|
+
buffer.put(payloadBytes.unsafeBytes(), payloadBytes.begin(), payloadSize);
|
110
|
+
}
|
111
|
+
return getRuntime().newString(new ByteList(bytes, binaryEncoding, false));
|
112
|
+
}
|
113
|
+
|
114
|
+
@JRubyMethod(name = {"to_s", "inspect"})
|
115
|
+
@Override
|
116
|
+
public IRubyObject to_s() {
|
117
|
+
IRubyObject payloadStr = payload.callMethod(getRuntime().getCurrentContext(), "inspect");
|
118
|
+
return getRuntime().newString(String.format("#<MessagePack::ExtensionValue @type=%d, @payload=%s>", type.getLongValue(), payloadStr));
|
119
|
+
}
|
120
|
+
|
121
|
+
@JRubyMethod(name = "hash")
|
122
|
+
@Override
|
123
|
+
public RubyFixnum hash() {
|
124
|
+
long hash = payload.hashCode() & (type.getLongValue() << 56);
|
125
|
+
return RubyFixnum.newFixnum(getRuntime(), hash);
|
126
|
+
}
|
127
|
+
|
128
|
+
@JRubyMethod(name = "eql?")
|
129
|
+
public IRubyObject eql_p(ThreadContext ctx, IRubyObject o) {
|
130
|
+
if (o instanceof ExtensionValue) {
|
131
|
+
ExtensionValue other = (ExtensionValue) o;
|
132
|
+
return getRuntime().newBoolean(this.type.callMethod(ctx, "eql?", other.type).isTrue() && this.payload.callMethod(ctx, "eql?", other.payload).isTrue());
|
133
|
+
}
|
134
|
+
return getRuntime().getFalse();
|
135
|
+
}
|
136
|
+
}
|
@@ -0,0 +1,113 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
import org.jruby.Ruby;
|
5
|
+
import org.jruby.RubyModule;
|
6
|
+
import org.jruby.RubyClass;
|
7
|
+
import org.jruby.RubyString;
|
8
|
+
import org.jruby.RubyNil;
|
9
|
+
import org.jruby.RubyBoolean;
|
10
|
+
import org.jruby.RubyHash;
|
11
|
+
import org.jruby.runtime.load.Library;
|
12
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
13
|
+
import org.jruby.runtime.ThreadContext;
|
14
|
+
import org.jruby.runtime.Block;
|
15
|
+
import org.jruby.runtime.Visibility;
|
16
|
+
import org.jruby.anno.JRubyModule;
|
17
|
+
import org.jruby.anno.JRubyMethod;
|
18
|
+
import org.jruby.internal.runtime.methods.CallConfiguration;
|
19
|
+
import org.jruby.internal.runtime.methods.DynamicMethod;
|
20
|
+
|
21
|
+
|
22
|
+
public class MessagePackLibrary implements Library {
|
23
|
+
public void load(Ruby runtime, boolean wrap) {
|
24
|
+
RubyModule msgpackModule = runtime.defineModule("MessagePack");
|
25
|
+
msgpackModule.defineAnnotatedMethods(MessagePackModule.class);
|
26
|
+
RubyClass standardErrorClass = runtime.getStandardError();
|
27
|
+
RubyClass unpackErrorClass = msgpackModule.defineClassUnder("UnpackError", standardErrorClass, standardErrorClass.getAllocator());
|
28
|
+
RubyClass underflowErrorClass = msgpackModule.defineClassUnder("UnderflowError", unpackErrorClass, unpackErrorClass.getAllocator());
|
29
|
+
RubyClass extensionValueClass = msgpackModule.defineClassUnder("ExtensionValue", runtime.getObject(), new ExtensionValue.ExtensionValueAllocator());
|
30
|
+
extensionValueClass.defineAnnotatedMethods(ExtensionValue.class);
|
31
|
+
RubyClass packerClass = msgpackModule.defineClassUnder("Packer", runtime.getObject(), new Packer.PackerAllocator());
|
32
|
+
packerClass.defineAnnotatedMethods(Packer.class);
|
33
|
+
RubyClass unpackerClass = msgpackModule.defineClassUnder("Unpacker", runtime.getObject(), new Unpacker.UnpackerAllocator());
|
34
|
+
unpackerClass.defineAnnotatedMethods(Unpacker.class);
|
35
|
+
RubyClass bufferClass = msgpackModule.defineClassUnder("Buffer", runtime.getObject(), new Buffer.BufferAllocator());
|
36
|
+
bufferClass.defineAnnotatedMethods(Buffer.class);
|
37
|
+
installCoreExtensions(runtime);
|
38
|
+
}
|
39
|
+
|
40
|
+
private void installCoreExtensions(Ruby runtime) {
|
41
|
+
installCoreExtensions(
|
42
|
+
runtime,
|
43
|
+
runtime.getNilClass(),
|
44
|
+
runtime.getTrueClass(),
|
45
|
+
runtime.getFalseClass(),
|
46
|
+
runtime.getFixnum(),
|
47
|
+
runtime.getBignum(),
|
48
|
+
runtime.getFloat(),
|
49
|
+
runtime.getString(),
|
50
|
+
runtime.getArray(),
|
51
|
+
runtime.getHash(),
|
52
|
+
runtime.getSymbol()
|
53
|
+
);
|
54
|
+
}
|
55
|
+
|
56
|
+
private void installCoreExtensions(Ruby runtime, RubyClass... classes) {
|
57
|
+
for (RubyClass cls : classes) {
|
58
|
+
cls.addMethod("to_msgpack", createToMsgpackMethod(runtime, cls));
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
private DynamicMethod createToMsgpackMethod(final Ruby runtime, RubyClass cls) {
|
63
|
+
return new DynamicMethod(cls, Visibility.PUBLIC, CallConfiguration.FrameNoneScopeNone) {
|
64
|
+
@Override
|
65
|
+
public IRubyObject call(ThreadContext context, IRubyObject recv, RubyModule clazz, String name, IRubyObject[] args, Block block) {
|
66
|
+
IRubyObject[] allArgs = new IRubyObject[1 + args.length];
|
67
|
+
allArgs[0] = recv;
|
68
|
+
System.arraycopy(args, 0, allArgs, 1, args.length);
|
69
|
+
return MessagePackModule.pack(runtime.getCurrentContext(), null, allArgs);
|
70
|
+
}
|
71
|
+
|
72
|
+
@Override
|
73
|
+
public DynamicMethod dup() {
|
74
|
+
return this;
|
75
|
+
}
|
76
|
+
};
|
77
|
+
}
|
78
|
+
|
79
|
+
@JRubyModule(name = "MessagePack")
|
80
|
+
public static class MessagePackModule {
|
81
|
+
@JRubyMethod(module = true, required = 1, optional = 1, alias = {"dump"})
|
82
|
+
public static IRubyObject pack(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) {
|
83
|
+
IRubyObject[] extraArgs = null;
|
84
|
+
if (args.length == 0) {
|
85
|
+
extraArgs = new IRubyObject[] {};
|
86
|
+
} else {
|
87
|
+
extraArgs = new IRubyObject[args.length - 1];
|
88
|
+
System.arraycopy(args, 1, extraArgs, 0, args.length - 1);
|
89
|
+
}
|
90
|
+
Packer packer = new Packer(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Packer"));
|
91
|
+
packer.initialize(ctx, extraArgs);
|
92
|
+
packer.write(ctx, args[0]);
|
93
|
+
return packer.toS(ctx);
|
94
|
+
}
|
95
|
+
|
96
|
+
@JRubyMethod(module = true, required = 1, optional = 1, alias = {"load"})
|
97
|
+
public static IRubyObject unpack(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) {
|
98
|
+
Decoder decoder = new Decoder(ctx.getRuntime(), args[0].asString().getBytes());
|
99
|
+
if (args.length > 1) {
|
100
|
+
if (args[args.length - 1] instanceof RubyHash) {
|
101
|
+
Ruby runtime = ctx.getRuntime();
|
102
|
+
IRubyObject symbolizeKeys = ((RubyHash) args[args.length - 1]).fastARef((IRubyObject) runtime.getSymbolTable().getSymbol("symbolize_keys"));
|
103
|
+
if (symbolizeKeys instanceof RubyNil || symbolizeKeys instanceof RubyBoolean.False) {
|
104
|
+
decoder.symbolizeKeys(false);
|
105
|
+
} else {
|
106
|
+
decoder.symbolizeKeys(true);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
return decoder.next();
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|