msgpack 0.6.0pre1-x64-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 +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +26 -0
- data/ChangeLog +117 -0
- data/Dockerfile +30 -0
- data/Gemfile +4 -0
- data/LICENSE +177 -0
- data/README.rdoc +129 -0
- data/Rakefile +114 -0
- data/bench/pack.rb +23 -0
- data/bench/pack_log.rb +33 -0
- data/bench/pack_log_long.rb +65 -0
- data/bench/run.sh +14 -0
- data/bench/run_long.sh +35 -0
- data/bench/unpack.rb +21 -0
- data/bench/unpack_log.rb +34 -0
- data/bench/unpack_log_long.rb +67 -0
- data/cross-build.sh +9 -0
- data/doclib/msgpack/buffer.rb +193 -0
- data/doclib/msgpack/core_ext.rb +101 -0
- data/doclib/msgpack/error.rb +14 -0
- data/doclib/msgpack/packer.rb +134 -0
- data/doclib/msgpack/unpacker.rb +146 -0
- data/doclib/msgpack.rb +77 -0
- 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 +308 -0
- data/ext/java/org/msgpack/jruby/ExtensionValue.java +136 -0
- data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +107 -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/ext/msgpack/buffer.c +695 -0
- data/ext/msgpack/buffer.h +447 -0
- data/ext/msgpack/buffer_class.c +507 -0
- data/ext/msgpack/buffer_class.h +32 -0
- data/ext/msgpack/compat.h +113 -0
- data/ext/msgpack/core_ext.c +129 -0
- data/ext/msgpack/core_ext.h +26 -0
- data/ext/msgpack/extconf.rb +28 -0
- data/ext/msgpack/packer.c +168 -0
- data/ext/msgpack/packer.h +441 -0
- data/ext/msgpack/packer_class.c +302 -0
- data/ext/msgpack/packer_class.h +30 -0
- data/ext/msgpack/rbinit.c +33 -0
- data/ext/msgpack/rmem.c +94 -0
- data/ext/msgpack/rmem.h +109 -0
- data/ext/msgpack/sysdep.h +115 -0
- data/ext/msgpack/sysdep_endian.h +50 -0
- data/ext/msgpack/sysdep_types.h +46 -0
- data/ext/msgpack/unpacker.c +771 -0
- data/ext/msgpack/unpacker.h +122 -0
- data/ext/msgpack/unpacker_class.c +405 -0
- data/ext/msgpack/unpacker_class.h +32 -0
- data/lib/msgpack/msgpack.so +0 -0
- data/lib/msgpack/version.rb +3 -0
- data/lib/msgpack.rb +13 -0
- data/msgpack.gemspec +31 -0
- data/msgpack.org.md +46 -0
- data/spec/cases.json +1 -0
- data/spec/cases.msg +0 -0
- data/spec/cases_compact.msg +0 -0
- data/spec/cases_spec.rb +39 -0
- data/spec/cruby/buffer_io_spec.rb +256 -0
- data/spec/cruby/buffer_packer.rb +29 -0
- data/spec/cruby/buffer_spec.rb +572 -0
- data/spec/cruby/buffer_unpacker.rb +19 -0
- data/spec/cruby/packer_spec.rb +120 -0
- data/spec/cruby/unpacker_spec.rb +305 -0
- data/spec/format_spec.rb +282 -0
- 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 +142 -0
- data/spec/pack_spec.rb +67 -0
- data/spec/random_compat.rb +24 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/unpack_spec.rb +60 -0
- metadata +209 -0
@@ -0,0 +1,308 @@
|
|
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(), runtime.getEncodingService().getEncoding(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
|
+
} else if (length <= 0xff) {
|
203
|
+
ensureRemainingCapacity(2 + length);
|
204
|
+
buffer.put(binary ? BIN8 : STR8);
|
205
|
+
buffer.put((byte) length);
|
206
|
+
} else if (length <= 0xffff) {
|
207
|
+
ensureRemainingCapacity(3 + length);
|
208
|
+
buffer.put(binary ? BIN16 : STR16);
|
209
|
+
buffer.putShort((short) length);
|
210
|
+
} else {
|
211
|
+
ensureRemainingCapacity(5 + length);
|
212
|
+
buffer.put(binary ? BIN32 : STR32);
|
213
|
+
buffer.putInt((int) length);
|
214
|
+
}
|
215
|
+
buffer.put(bytes.unsafeBytes(), bytes.begin(), length);
|
216
|
+
}
|
217
|
+
|
218
|
+
private void appendArray(RubyArray object) {
|
219
|
+
appendArrayHeader(object);
|
220
|
+
appendArrayElements(object);
|
221
|
+
}
|
222
|
+
|
223
|
+
private void appendArrayHeader(RubyArray object) {
|
224
|
+
appendArrayHeader(object.size());
|
225
|
+
}
|
226
|
+
|
227
|
+
private void appendArrayHeader(int size) {
|
228
|
+
if (size < 16) {
|
229
|
+
ensureRemainingCapacity(1);
|
230
|
+
buffer.put((byte) (size | 0x90));
|
231
|
+
} else if (size < 0x10000) {
|
232
|
+
ensureRemainingCapacity(3);
|
233
|
+
buffer.put(ARY16);
|
234
|
+
buffer.putShort((short) size);
|
235
|
+
} else {
|
236
|
+
ensureRemainingCapacity(5);
|
237
|
+
buffer.put(ARY32);
|
238
|
+
buffer.putInt(size);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
|
242
|
+
private void appendArrayElements(RubyArray object) {
|
243
|
+
int size = object.size();
|
244
|
+
for (int i = 0; i < size; i++) {
|
245
|
+
appendObject(object.eltOk(i));
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
private void appendHash(RubyHash object) {
|
250
|
+
appendHashHeader(object);
|
251
|
+
appendHashElements(object);
|
252
|
+
}
|
253
|
+
|
254
|
+
private void appendHashHeader(RubyHash object) {
|
255
|
+
appendHashHeader(object.size());
|
256
|
+
}
|
257
|
+
|
258
|
+
private void appendHashHeader(int size) {
|
259
|
+
if (size < 16) {
|
260
|
+
ensureRemainingCapacity(1);
|
261
|
+
buffer.put((byte) (size | 0x80));
|
262
|
+
} else if (size < 0x10000) {
|
263
|
+
ensureRemainingCapacity(3);
|
264
|
+
buffer.put(MAP16);
|
265
|
+
buffer.putShort((short) size);
|
266
|
+
} else {
|
267
|
+
ensureRemainingCapacity(5);
|
268
|
+
buffer.put(MAP32);
|
269
|
+
buffer.putInt(size);
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
private void appendHashElements(RubyHash object) {
|
274
|
+
int size = object.size();
|
275
|
+
HashVisitor visitor = new HashVisitor(size);
|
276
|
+
object.visitAll(visitor);
|
277
|
+
if (visitor.remain != 0) {
|
278
|
+
object.getRuntime().newConcurrencyError("Hash size changed while packing");
|
279
|
+
}
|
280
|
+
}
|
281
|
+
|
282
|
+
private class HashVisitor extends RubyHash.Visitor {
|
283
|
+
public int remain;
|
284
|
+
|
285
|
+
public HashVisitor(int size) {
|
286
|
+
remain = size;
|
287
|
+
}
|
288
|
+
|
289
|
+
public void visit(IRubyObject key, IRubyObject value) {
|
290
|
+
if (remain-- > 0) {
|
291
|
+
appendObject(key);
|
292
|
+
appendObject(value);
|
293
|
+
}
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
297
|
+
private void appendCustom(IRubyObject object, IRubyObject destination) {
|
298
|
+
if (destination == null) {
|
299
|
+
IRubyObject result = object.callMethod(runtime.getCurrentContext(), "to_msgpack");
|
300
|
+
ByteList bytes = result.asString().getByteList();
|
301
|
+
int length = bytes.length();
|
302
|
+
ensureRemainingCapacity(length);
|
303
|
+
buffer.put(bytes.unsafeBytes(), bytes.begin(), length);
|
304
|
+
} else {
|
305
|
+
object.callMethod(runtime.getCurrentContext(), "to_msgpack", destination);
|
306
|
+
}
|
307
|
+
}
|
308
|
+
}
|
@@ -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,107 @@
|
|
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 && !args[args.length - 1].isNil()) {
|
100
|
+
RubyHash hash = args[args.length - 1].convertToHash();
|
101
|
+
IRubyObject symbolizeKeys = hash.fastARef(ctx.getRuntime().newSymbol("symbolize_keys"));
|
102
|
+
decoder.symbolizeKeys(symbolizeKeys != null && symbolizeKeys.isTrue());
|
103
|
+
}
|
104
|
+
return decoder.next();
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
import org.jruby.Ruby;
|
5
|
+
import org.jruby.RubyClass;
|
6
|
+
import org.jruby.RubyObject;
|
7
|
+
import org.jruby.RubyHash;
|
8
|
+
import org.jruby.RubyIO;
|
9
|
+
import org.jruby.RubyInteger;
|
10
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
11
|
+
import org.jruby.anno.JRubyClass;
|
12
|
+
import org.jruby.anno.JRubyMethod;
|
13
|
+
import org.jruby.runtime.ThreadContext;
|
14
|
+
import org.jruby.runtime.ObjectAllocator;
|
15
|
+
import org.jruby.util.ByteList;
|
16
|
+
|
17
|
+
|
18
|
+
@JRubyClass(name="MessagePack::Packer")
|
19
|
+
public class Packer extends RubyObject {
|
20
|
+
private Buffer buffer;
|
21
|
+
private Encoder encoder;
|
22
|
+
|
23
|
+
public Packer(Ruby runtime, RubyClass type) {
|
24
|
+
super(runtime, type);
|
25
|
+
}
|
26
|
+
|
27
|
+
static class PackerAllocator implements ObjectAllocator {
|
28
|
+
public IRubyObject allocate(Ruby runtime, RubyClass type) {
|
29
|
+
return new Packer(runtime, type);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
@JRubyMethod(name = "initialize", optional = 2)
|
34
|
+
public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
|
35
|
+
this.encoder = new Encoder(ctx.getRuntime());
|
36
|
+
this.buffer = new Buffer(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Buffer"));
|
37
|
+
this.buffer.initialize(ctx, args);
|
38
|
+
return this;
|
39
|
+
}
|
40
|
+
|
41
|
+
@JRubyMethod(name = "write")
|
42
|
+
public IRubyObject write(ThreadContext ctx, IRubyObject obj) {
|
43
|
+
return buffer.write(ctx, encoder.encode(obj, this));
|
44
|
+
}
|
45
|
+
|
46
|
+
@JRubyMethod(name = "write_nil")
|
47
|
+
public IRubyObject writeNil(ThreadContext ctx) {
|
48
|
+
return write(ctx, null);
|
49
|
+
}
|
50
|
+
|
51
|
+
@JRubyMethod(name = "write_array_header")
|
52
|
+
public IRubyObject writeArrayHeader(ThreadContext ctx, IRubyObject size) {
|
53
|
+
int s = (int) size.convertToInteger().getLongValue();
|
54
|
+
return buffer.write(ctx, encoder.encodeArrayHeader(s));
|
55
|
+
}
|
56
|
+
|
57
|
+
@JRubyMethod(name = "write_map_header")
|
58
|
+
public IRubyObject writeMapHeader(ThreadContext ctx, IRubyObject size) {
|
59
|
+
int s = (int) size.convertToInteger().getLongValue();
|
60
|
+
return buffer.write(ctx, encoder.encodeMapHeader(s));
|
61
|
+
}
|
62
|
+
|
63
|
+
@JRubyMethod(name = "to_s")
|
64
|
+
public IRubyObject toS(ThreadContext ctx) {
|
65
|
+
return buffer.toS(ctx);
|
66
|
+
}
|
67
|
+
|
68
|
+
@JRubyMethod(name = "buffer")
|
69
|
+
public IRubyObject buffer(ThreadContext ctx) {
|
70
|
+
return buffer;
|
71
|
+
}
|
72
|
+
|
73
|
+
@JRubyMethod(name = "flush")
|
74
|
+
public IRubyObject flush(ThreadContext ctx) {
|
75
|
+
return buffer.flush(ctx);
|
76
|
+
}
|
77
|
+
|
78
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
public interface Types {
|
5
|
+
public static final byte FIXSTR = (byte) 0xa0; // This is actually not header byte, but prefix bit mask
|
6
|
+
public static final byte NIL = (byte) 0xc0;
|
7
|
+
public static final byte FALSE = (byte) 0xc2;
|
8
|
+
public static final byte TRUE = (byte) 0xc3;
|
9
|
+
public static final byte BIN8 = (byte) 0xc4;
|
10
|
+
public static final byte BIN16 = (byte) 0xc5;
|
11
|
+
public static final byte BIN32 = (byte) 0xc6;
|
12
|
+
public static final byte VAREXT8 = (byte) 0xc7;
|
13
|
+
public static final byte VAREXT16 = (byte) 0xc8;
|
14
|
+
public static final byte VAREXT32 = (byte) 0xc9;
|
15
|
+
public static final byte FLOAT32 = (byte) 0xca;
|
16
|
+
public static final byte FLOAT64 = (byte) 0xcb;
|
17
|
+
public static final byte UINT8 = (byte) 0xcc;
|
18
|
+
public static final byte UINT16 = (byte) 0xcd;
|
19
|
+
public static final byte UINT32 = (byte) 0xce;
|
20
|
+
public static final byte UINT64 = (byte) 0xcf;
|
21
|
+
public static final byte INT8 = (byte) 0xd0;
|
22
|
+
public static final byte INT16 = (byte) 0xd1;
|
23
|
+
public static final byte INT32 = (byte) 0xd2;
|
24
|
+
public static final byte INT64 = (byte) 0xd3;
|
25
|
+
public static final byte FIXEXT1 = (byte) 0xd4;
|
26
|
+
public static final byte FIXEXT2 = (byte) 0xd5;
|
27
|
+
public static final byte FIXEXT4 = (byte) 0xd6;
|
28
|
+
public static final byte FIXEXT8 = (byte) 0xd7;
|
29
|
+
public static final byte FIXEXT16 = (byte) 0xd8;
|
30
|
+
public static final byte STR8 = (byte) 0xd9;
|
31
|
+
public static final byte STR16 = (byte) 0xda;
|
32
|
+
public static final byte STR32 = (byte) 0xdb;
|
33
|
+
public static final byte ARY16 = (byte) 0xdc;
|
34
|
+
public static final byte ARY32 = (byte) 0xdd;
|
35
|
+
public static final byte MAP16 = (byte) 0xde;
|
36
|
+
public static final byte MAP32 = (byte) 0xdf;
|
37
|
+
}
|