msgpack-jruby 1.0.0-java → 1.1.3-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -2
- data/.rvmrc +1 -1
- data/Gemfile +3 -1
- data/Gemfile.lock +52 -0
- data/Rakefile +45 -11
- data/ext/.gitignore +1 -0
- data/ext/java/MsgpackJrubyService.java +15 -0
- data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +229 -0
- data/ext/java/org/msgpack/jruby/RubyObjectPacker.java +111 -0
- data/ext/java/org/msgpack/jruby/RubyObjectUnpacker.java +114 -0
- data/lib/ext/javassist-3.15.0-GA.jar +0 -0
- data/lib/ext/msgpack-0.6.6.jar +0 -0
- data/lib/ext/msgpack_jruby.jar +0 -0
- data/lib/msgpack/version.rb +1 -1
- data/lib/msgpack.rb +5 -4
- data/spec/benchmark.rb +11 -5
- data/spec/msgpack/unpacker_spec.rb +159 -0
- data/spec/msgpack_spec.rb +6 -1
- metadata +38 -44
- data/ext/java/org/msgpack/jruby/MessagePack.java +0 -156
- data/lib/ext/msgpack-0.5.2-devel.jar +0 -0
- data/lib/ext/org/msgpack/jruby/MessagePack.class +0 -0
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm --create use jruby-1.6.
|
1
|
+
rvm --create use jruby-1.6.7@msgpack-jruby
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
alf (0.10.1)
|
5
|
+
highline (~> 1.6.2)
|
6
|
+
myrrha (~> 1.2.1)
|
7
|
+
quickl (~> 0.4.1)
|
8
|
+
bouncy-castle-java (1.5.0146.1)
|
9
|
+
bson (1.5.2)
|
10
|
+
bson (1.5.2-java)
|
11
|
+
bson_ext (1.5.2)
|
12
|
+
bson (= 1.5.2)
|
13
|
+
diff-lcs (1.1.3)
|
14
|
+
ffi (1.0.9)
|
15
|
+
ffi (1.0.9-java)
|
16
|
+
ffi-ncurses (0.3.3)
|
17
|
+
ffi (>= 0.6.3)
|
18
|
+
gnuplot (2.3.6)
|
19
|
+
highline (1.6.2)
|
20
|
+
jruby-openssl (0.7.4)
|
21
|
+
bouncy-castle-java
|
22
|
+
json (1.5.0)
|
23
|
+
json (1.5.0-java)
|
24
|
+
msgpack (0.4.6)
|
25
|
+
myrrha (1.2.1)
|
26
|
+
quickl (0.4.1)
|
27
|
+
rspec (2.6.0)
|
28
|
+
rspec-core (~> 2.6.0)
|
29
|
+
rspec-expectations (~> 2.6.0)
|
30
|
+
rspec-mocks (~> 2.6.0)
|
31
|
+
rspec-core (2.6.4)
|
32
|
+
rspec-expectations (2.6.0)
|
33
|
+
diff-lcs (~> 1.1.2)
|
34
|
+
rspec-mocks (2.6.0)
|
35
|
+
viiite (0.1.0)
|
36
|
+
alf (~> 0.10.0)
|
37
|
+
gnuplot (~> 2.3.6)
|
38
|
+
quickl (~> 0.4.0)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
java
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
bson
|
46
|
+
bson_ext
|
47
|
+
ffi-ncurses
|
48
|
+
jruby-openssl
|
49
|
+
json
|
50
|
+
msgpack
|
51
|
+
rspec
|
52
|
+
viiite
|
data/Rakefile
CHANGED
@@ -1,22 +1,56 @@
|
|
1
|
-
|
1
|
+
$: << 'lib'
|
2
2
|
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'msgpack/version'
|
3
5
|
|
4
|
-
Bundler::GemHelper.install_tasks
|
5
6
|
|
6
7
|
task :clean do
|
7
|
-
rm Dir['
|
8
|
+
rm Dir['ext/java/**/*.class']
|
8
9
|
end
|
9
10
|
|
10
11
|
task :compile do
|
11
|
-
|
12
|
+
classpath = (Dir["lib/ext/*.jar"] + ["#{ENV['MY_RUBY_HOME']}/lib/jruby.jar"]).join(':')
|
13
|
+
system %(javac -Xlint:-options -source 1.6 -target 1.6 -cp #{classpath} ext/java/*.java ext/java/org/msgpack/jruby/*.java)
|
14
|
+
exit($?.exitstatus) unless $?.success?
|
12
15
|
end
|
13
16
|
|
14
|
-
|
15
|
-
|
17
|
+
task :package => :compile do
|
18
|
+
class_files = Dir['ext/java/**/*.class'].map { |path| path = path.sub('ext/java/', ''); "-C ext/java '#{path}'" }
|
19
|
+
system %(jar cf lib/ext/msgpack_jruby.jar #{class_files.join(' ')})
|
20
|
+
exit($?.exitstatus) unless $?.success?
|
21
|
+
end
|
16
22
|
|
17
|
-
task :
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
23
|
+
task :release do
|
24
|
+
version_string = "v#{MessagePack::VERSION}"
|
25
|
+
unless %x(git tag -l).include?(version_string)
|
26
|
+
system %(git tag -a #{version_string} -m #{version_string})
|
27
|
+
end
|
28
|
+
system %(gem build msgpack-jruby.gemspec && gem push msgpack-jruby-*.gem && mv msgpack-jruby-*.gem pkg)
|
22
29
|
end
|
30
|
+
|
31
|
+
namespace :benchmark do
|
32
|
+
BENCHMARK_RUBIES = ['1.9.2-p0', 'jruby-1.6.5', 'jruby-head']
|
33
|
+
BENCHMARK_GEMSET = 'msgpack-jruby-benchmarking'
|
34
|
+
|
35
|
+
task :run do
|
36
|
+
rubies = BENCHMARK_RUBIES.map { |rb| "#{rb}@#{BENCHMARK_GEMSET}" }
|
37
|
+
cmd = %(rvm #{rubies.join(',')} exec viiite run spec/benchmark.rb | tee benchmark | viiite report --hierarchy --regroup=bench,lib,ruby)
|
38
|
+
puts cmd
|
39
|
+
system cmd
|
40
|
+
end
|
41
|
+
|
42
|
+
task :quick do
|
43
|
+
cmd = %(IMPLEMENTATIONS=msgpack viiite run spec/benchmark.rb | viiite report --hierarchy --regroup=bench)
|
44
|
+
puts cmd
|
45
|
+
system cmd
|
46
|
+
end
|
47
|
+
|
48
|
+
task :setup do
|
49
|
+
rubies = BENCHMARK_RUBIES.map { |rb| "#{rb}@#{BENCHMARK_GEMSET}" }
|
50
|
+
rubies.each do |ruby_version|
|
51
|
+
cmd = %(rvm-shell #{ruby_version} -c 'bundle check || bundle install')
|
52
|
+
puts cmd
|
53
|
+
system cmd
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/ext/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.class
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import java.io.IOException;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.runtime.load.BasicLibraryService;
|
5
|
+
|
6
|
+
import org.msgpack.jruby.MessagePackLibrary;
|
7
|
+
|
8
|
+
|
9
|
+
public class MsgpackJrubyService implements BasicLibraryService {
|
10
|
+
public boolean basicLoad(final Ruby runtime) throws IOException {
|
11
|
+
new MessagePackLibrary().load(runtime, false);
|
12
|
+
return true;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
@@ -0,0 +1,229 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
import java.io.InputStream;
|
5
|
+
import java.io.ByteArrayInputStream;
|
6
|
+
import java.io.IOException;
|
7
|
+
|
8
|
+
import org.jruby.Ruby;
|
9
|
+
import org.jruby.RubyModule;
|
10
|
+
import org.jruby.RubyClass;
|
11
|
+
import org.jruby.RubyString;
|
12
|
+
import org.jruby.RubyObject;
|
13
|
+
import org.jruby.RubyIO;
|
14
|
+
import org.jruby.RubyStringIO;
|
15
|
+
import org.jruby.RubyNumeric;
|
16
|
+
import org.jruby.RubyEnumerator;
|
17
|
+
import org.jruby.runtime.load.Library;
|
18
|
+
import org.jruby.runtime.callback.Callback;
|
19
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
20
|
+
import org.jruby.runtime.Arity;
|
21
|
+
import org.jruby.runtime.Block;
|
22
|
+
import org.jruby.runtime.ObjectAllocator;
|
23
|
+
import org.jruby.runtime.ThreadContext;
|
24
|
+
import org.jruby.anno.JRubyClass;
|
25
|
+
import org.jruby.anno.JRubyModule;
|
26
|
+
import org.jruby.anno.JRubyMethod;
|
27
|
+
import org.jruby.util.IOInputStream;
|
28
|
+
|
29
|
+
import static org.jruby.runtime.Visibility.*;
|
30
|
+
|
31
|
+
import org.msgpack.MessagePack;
|
32
|
+
import org.msgpack.packer.BufferPacker;
|
33
|
+
import org.msgpack.packer.Packer;
|
34
|
+
import org.msgpack.unpacker.MessagePackBufferUnpacker;
|
35
|
+
import org.msgpack.unpacker.MessagePackUnpacker;
|
36
|
+
import org.msgpack.unpacker.UnpackerIterator;
|
37
|
+
import org.msgpack.type.Value;
|
38
|
+
import org.msgpack.io.Input;
|
39
|
+
import org.msgpack.io.LinkedBufferInput;
|
40
|
+
import org.msgpack.io.StreamInput;
|
41
|
+
|
42
|
+
|
43
|
+
public class MessagePackLibrary implements Library {
|
44
|
+
public void load(Ruby runtime, boolean wrap) throws IOException {
|
45
|
+
MessagePack msgPack = new MessagePack();
|
46
|
+
RubyModule msgpackModule = runtime.defineModule("MessagePack");
|
47
|
+
msgpackModule.defineAnnotatedMethods(MessagePackModule.class);
|
48
|
+
RubyClass standardErrorClass = runtime.getStandardError();
|
49
|
+
RubyClass unpackErrorClass = msgpackModule.defineClassUnder("UnpackError", standardErrorClass, standardErrorClass.getAllocator());
|
50
|
+
RubyClass unpackerClass = msgpackModule.defineClassUnder("Unpacker", runtime.getObject(), new UnpackerAllocator(msgPack));
|
51
|
+
unpackerClass.defineAnnotatedMethods(Unpacker.class);
|
52
|
+
}
|
53
|
+
|
54
|
+
@JRubyModule(name = "MessagePack")
|
55
|
+
public static class MessagePackModule {
|
56
|
+
private static MessagePack msgPack = new MessagePack();
|
57
|
+
private static RubyObjectUnpacker unpacker = new RubyObjectUnpacker(msgPack);
|
58
|
+
|
59
|
+
@JRubyMethod(module = true, required = 1)
|
60
|
+
public static IRubyObject pack(ThreadContext ctx, IRubyObject recv, IRubyObject obj) throws IOException {
|
61
|
+
BufferPacker bufferedPacker = msgPack.createBufferPacker();
|
62
|
+
Packer packer = new RubyObjectPacker(msgPack, bufferedPacker).write(obj);
|
63
|
+
return RubyString.newString(ctx.getRuntime(), bufferedPacker.toByteArray());
|
64
|
+
}
|
65
|
+
|
66
|
+
@JRubyMethod(module = true, required = 1)
|
67
|
+
public static IRubyObject unpack(ThreadContext ctx, IRubyObject recv, IRubyObject obj) throws IOException {
|
68
|
+
return unpacker.unpack(obj.asString());
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
private static class UnpackerAllocator implements ObjectAllocator {
|
73
|
+
private MessagePack msgPack;
|
74
|
+
|
75
|
+
public UnpackerAllocator(MessagePack msgPack) {
|
76
|
+
this.msgPack = msgPack;
|
77
|
+
}
|
78
|
+
|
79
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
80
|
+
return new Unpacker(runtime, klass, msgPack);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
@JRubyClass(name="MessagePack::Unpacker")
|
85
|
+
public static class Unpacker extends RubyObject {
|
86
|
+
private MessagePack msgPack;
|
87
|
+
private RubyObjectUnpacker rubyObjectUnpacker;
|
88
|
+
private MessagePackBufferUnpacker bufferUnpacker;
|
89
|
+
private MessagePackUnpacker streamUnpacker;
|
90
|
+
private IRubyObject stream;
|
91
|
+
private IRubyObject data;
|
92
|
+
|
93
|
+
public Unpacker(Ruby runtime, RubyClass type, MessagePack msgPack) {
|
94
|
+
super(runtime, type);
|
95
|
+
this.msgPack = msgPack;
|
96
|
+
this.rubyObjectUnpacker = new RubyObjectUnpacker(msgPack);
|
97
|
+
this.bufferUnpacker = null;
|
98
|
+
this.streamUnpacker = null;
|
99
|
+
this.stream = null;
|
100
|
+
this.data = null;
|
101
|
+
}
|
102
|
+
|
103
|
+
@JRubyMethod(name = "initialize", optional = 1, visibility = PRIVATE)
|
104
|
+
public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
|
105
|
+
if (args.length > 0) {
|
106
|
+
setStream(ctx, args[0]);
|
107
|
+
}
|
108
|
+
return this;
|
109
|
+
}
|
110
|
+
|
111
|
+
@JRubyMethod(required = 2)
|
112
|
+
public IRubyObject execute(ThreadContext ctx, IRubyObject data, IRubyObject offset) {
|
113
|
+
return executeLimit(ctx, data, offset, null);
|
114
|
+
}
|
115
|
+
|
116
|
+
@JRubyMethod(name = "execute_limit", required = 3)
|
117
|
+
public IRubyObject executeLimit(ThreadContext ctx, IRubyObject data, IRubyObject offset, IRubyObject limit) {
|
118
|
+
this.data = null;
|
119
|
+
try {
|
120
|
+
int jOffset = RubyNumeric.fix2int(offset);
|
121
|
+
int jLimit = -1;
|
122
|
+
if (limit != null) {
|
123
|
+
jLimit = RubyNumeric.fix2int(limit);
|
124
|
+
}
|
125
|
+
byte[] bytes = data.asString().getBytes();
|
126
|
+
MessagePackBufferUnpacker localBufferUnpacker = new MessagePackBufferUnpacker(msgPack, bytes.length);
|
127
|
+
localBufferUnpacker.wrap(bytes, jOffset, jLimit == -1 ? bytes.length - jOffset : jLimit);
|
128
|
+
this.data = rubyObjectUnpacker.valueToRubyObject(ctx.getRuntime(), localBufferUnpacker.readValue());
|
129
|
+
return ctx.getRuntime().newFixnum(jOffset + localBufferUnpacker.getReadByteCount());
|
130
|
+
} catch (IOException ioe) {
|
131
|
+
// TODO: how to throw Ruby exceptions?
|
132
|
+
return ctx.getRuntime().getNil();
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
@JRubyMethod(name = "data")
|
137
|
+
public IRubyObject getData(ThreadContext ctx) {
|
138
|
+
if (data == null) {
|
139
|
+
return ctx.getRuntime().getNil();
|
140
|
+
} else {
|
141
|
+
return data;
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
@JRubyMethod(name = "finished?")
|
146
|
+
public IRubyObject finished_q(ThreadContext ctx) {
|
147
|
+
return data == null ? ctx.getRuntime().getFalse() : ctx.getRuntime().getTrue();
|
148
|
+
}
|
149
|
+
|
150
|
+
@JRubyMethod(required = 1)
|
151
|
+
public IRubyObject feed(ThreadContext ctx, IRubyObject data) {
|
152
|
+
streamUnpacker = null;
|
153
|
+
byte[] bytes = data.asString().getBytes();
|
154
|
+
if (bufferUnpacker == null) {
|
155
|
+
bufferUnpacker = new MessagePackBufferUnpacker(msgPack);
|
156
|
+
}
|
157
|
+
bufferUnpacker.feed(bytes);
|
158
|
+
return ctx.getRuntime().getNil();
|
159
|
+
}
|
160
|
+
|
161
|
+
@JRubyMethod(name = "feed_each", required = 1)
|
162
|
+
public IRubyObject feedEach(ThreadContext ctx, IRubyObject data, Block block) {
|
163
|
+
feed(ctx, data);
|
164
|
+
each(ctx, block);
|
165
|
+
return ctx.getRuntime().getNil();
|
166
|
+
}
|
167
|
+
|
168
|
+
@JRubyMethod
|
169
|
+
public IRubyObject each(ThreadContext ctx, Block block) {
|
170
|
+
MessagePackUnpacker localUnpacker = null;
|
171
|
+
if (bufferUnpacker == null && streamUnpacker != null) {
|
172
|
+
localUnpacker = streamUnpacker;
|
173
|
+
} else if (bufferUnpacker != null) {
|
174
|
+
localUnpacker = bufferUnpacker;
|
175
|
+
} else {
|
176
|
+
return ctx.getRuntime().getNil();
|
177
|
+
}
|
178
|
+
if (block.isGiven()) {
|
179
|
+
for (Value value : localUnpacker) {
|
180
|
+
IRubyObject rubyObject = rubyObjectUnpacker.valueToRubyObject(ctx.getRuntime(), value);
|
181
|
+
block.yield(ctx, rubyObject);
|
182
|
+
}
|
183
|
+
return ctx.getRuntime().getNil();
|
184
|
+
} else {
|
185
|
+
return RubyEnumerator.RubyEnumeratorKernel.obj_to_enum(ctx, this, Block.NULL_BLOCK);
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
@JRubyMethod
|
190
|
+
public IRubyObject fill(ThreadContext ctx) {
|
191
|
+
return ctx.getRuntime().getNil();
|
192
|
+
}
|
193
|
+
|
194
|
+
@JRubyMethod
|
195
|
+
public IRubyObject reset(ThreadContext ctx) {
|
196
|
+
if (bufferUnpacker != null) {
|
197
|
+
bufferUnpacker.reset();
|
198
|
+
}
|
199
|
+
if (streamUnpacker != null) {
|
200
|
+
streamUnpacker.reset();
|
201
|
+
}
|
202
|
+
return ctx.getRuntime().getNil();
|
203
|
+
}
|
204
|
+
|
205
|
+
@JRubyMethod(name = "stream")
|
206
|
+
public IRubyObject getStream(ThreadContext ctx) {
|
207
|
+
if (stream == null) {
|
208
|
+
return ctx.getRuntime().getNil();
|
209
|
+
} else {
|
210
|
+
return stream;
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
@JRubyMethod(name = "stream=", required = 1)
|
215
|
+
public IRubyObject setStream(ThreadContext ctx, IRubyObject stream) {
|
216
|
+
bufferUnpacker = null;
|
217
|
+
this.stream = stream;
|
218
|
+
if (stream instanceof RubyStringIO) {
|
219
|
+
// TODO: RubyStringIO returns negative numbers when read through IOInputStream#read
|
220
|
+
IRubyObject str = ((RubyStringIO) stream).string();
|
221
|
+
byte[] bytes = ((RubyString) str).getBytes();
|
222
|
+
streamUnpacker = new MessagePackUnpacker(msgPack, new ByteArrayInputStream(bytes));
|
223
|
+
} else {
|
224
|
+
streamUnpacker = new MessagePackUnpacker(msgPack, new IOInputStream(stream));
|
225
|
+
}
|
226
|
+
return getStream(ctx);
|
227
|
+
}
|
228
|
+
}
|
229
|
+
}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
import java.io.IOException;
|
5
|
+
|
6
|
+
import org.msgpack.MessagePack;
|
7
|
+
import org.msgpack.packer.Packer;
|
8
|
+
import org.msgpack.packer.MessagePackBufferPacker;
|
9
|
+
|
10
|
+
import org.jruby.RubyObject;
|
11
|
+
import org.jruby.RubyNil;
|
12
|
+
import org.jruby.RubyBoolean;
|
13
|
+
import org.jruby.RubyBignum;
|
14
|
+
import org.jruby.RubyInteger;
|
15
|
+
import org.jruby.RubyFixnum;
|
16
|
+
import org.jruby.RubyFloat;
|
17
|
+
import org.jruby.RubyString;
|
18
|
+
import org.jruby.RubySymbol;
|
19
|
+
import org.jruby.RubyArray;
|
20
|
+
import org.jruby.RubyHash;
|
21
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
22
|
+
|
23
|
+
|
24
|
+
public class RubyObjectPacker extends MessagePackBufferPacker {
|
25
|
+
private final Packer packer;
|
26
|
+
|
27
|
+
public RubyObjectPacker(MessagePack msgPack, Packer packer) {
|
28
|
+
super(msgPack);
|
29
|
+
this.packer = packer;
|
30
|
+
}
|
31
|
+
|
32
|
+
public Packer write(IRubyObject o) throws IOException {
|
33
|
+
if (o == null || o instanceof RubyNil) {
|
34
|
+
packer.writeNil();
|
35
|
+
return this;
|
36
|
+
} else if (o instanceof RubyBoolean) {
|
37
|
+
packer.write(((RubyBoolean) o).isTrue());
|
38
|
+
return this;
|
39
|
+
} else if (o instanceof RubyBignum) {
|
40
|
+
return write((RubyBignum) o);
|
41
|
+
} else if (o instanceof RubyInteger) {
|
42
|
+
return write((RubyInteger) o);
|
43
|
+
} else if (o instanceof RubyFixnum) {
|
44
|
+
return write((RubyFixnum) o);
|
45
|
+
} else if (o instanceof RubyFloat) {
|
46
|
+
return write((RubyFloat) o);
|
47
|
+
} else if (o instanceof RubyString) {
|
48
|
+
return write((RubyString) o);
|
49
|
+
} else if (o instanceof RubySymbol) {
|
50
|
+
return write((RubySymbol) o);
|
51
|
+
} else if (o instanceof RubyArray) {
|
52
|
+
return write((RubyArray) o);
|
53
|
+
} else if (o instanceof RubyHash) {
|
54
|
+
return write((RubyHash) o);
|
55
|
+
} else {
|
56
|
+
throw o.getRuntime().newArgumentError(String.format("Cannot pack type: %s", o.getClass().getName()));
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
public final Packer write(RubyBignum bignum) throws IOException {
|
61
|
+
packer.write(bignum.getBigIntegerValue());
|
62
|
+
return this;
|
63
|
+
}
|
64
|
+
|
65
|
+
public final Packer write(RubyInteger integer) throws IOException {
|
66
|
+
packer.write(integer.getLongValue());
|
67
|
+
return this;
|
68
|
+
}
|
69
|
+
|
70
|
+
public final Packer write(RubyFixnum fixnum) throws IOException {
|
71
|
+
packer.write(fixnum.getLongValue());
|
72
|
+
return this;
|
73
|
+
}
|
74
|
+
|
75
|
+
public final Packer write(RubyFloat flt) throws IOException {
|
76
|
+
packer.write(flt.getDoubleValue());
|
77
|
+
return this;
|
78
|
+
}
|
79
|
+
|
80
|
+
public final Packer write(RubyString str) throws IOException {
|
81
|
+
packer.write(str.getBytes());
|
82
|
+
return this;
|
83
|
+
}
|
84
|
+
|
85
|
+
public final Packer write(RubySymbol sym) throws IOException {
|
86
|
+
return write((RubyString) sym.to_s());
|
87
|
+
}
|
88
|
+
|
89
|
+
public final Packer write(RubyArray array) throws IOException {
|
90
|
+
int count = array.size();
|
91
|
+
packer.writeArrayBegin(count);
|
92
|
+
for (int i = 0; i < count; i++) {
|
93
|
+
write((RubyObject) array.entry(i));
|
94
|
+
}
|
95
|
+
packer.writeArrayEnd();
|
96
|
+
return this;
|
97
|
+
}
|
98
|
+
|
99
|
+
public final Packer write(RubyHash hash) throws IOException {
|
100
|
+
int count = hash.size();
|
101
|
+
packer.writeMapBegin(count);
|
102
|
+
RubyArray keys = hash.keys();
|
103
|
+
RubyArray values = hash.rb_values();
|
104
|
+
for (int i = 0; i < count; i++) {
|
105
|
+
write((RubyObject) keys.entry(i));
|
106
|
+
write((RubyObject) values.entry(i));
|
107
|
+
}
|
108
|
+
packer.writeMapEnd();
|
109
|
+
return this;
|
110
|
+
}
|
111
|
+
}
|
@@ -0,0 +1,114 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
import java.io.IOException;
|
5
|
+
|
6
|
+
import org.msgpack.MessagePack;
|
7
|
+
import org.msgpack.MessageTypeException;
|
8
|
+
import org.msgpack.unpacker.MessagePackBufferUnpacker;
|
9
|
+
import org.msgpack.type.Value;
|
10
|
+
import org.msgpack.type.ValueType;
|
11
|
+
import org.msgpack.type.BooleanValue;
|
12
|
+
import org.msgpack.type.IntegerValue;
|
13
|
+
import org.msgpack.type.FloatValue;
|
14
|
+
import org.msgpack.type.ArrayValue;
|
15
|
+
import org.msgpack.type.MapValue;
|
16
|
+
import org.msgpack.type.RawValue;
|
17
|
+
|
18
|
+
import org.jruby.Ruby;
|
19
|
+
import org.jruby.RubyObject;
|
20
|
+
import org.jruby.RubyNil;
|
21
|
+
import org.jruby.RubyBoolean;
|
22
|
+
import org.jruby.RubyBignum;
|
23
|
+
import org.jruby.RubyInteger;
|
24
|
+
import org.jruby.RubyFixnum;
|
25
|
+
import org.jruby.RubyFloat;
|
26
|
+
import org.jruby.RubyString;
|
27
|
+
import org.jruby.RubySymbol;
|
28
|
+
import org.jruby.RubyArray;
|
29
|
+
import org.jruby.RubyHash;
|
30
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
31
|
+
|
32
|
+
|
33
|
+
public class RubyObjectUnpacker {
|
34
|
+
private final MessagePack msgPack;
|
35
|
+
|
36
|
+
public RubyObjectUnpacker(MessagePack msgPack) {
|
37
|
+
this.msgPack = msgPack;
|
38
|
+
}
|
39
|
+
|
40
|
+
public IRubyObject unpack(RubyString str) throws IOException {
|
41
|
+
return unpack(str.getRuntime(), str.getBytes());
|
42
|
+
}
|
43
|
+
|
44
|
+
public IRubyObject unpack(Ruby runtime, byte[] data) throws IOException {
|
45
|
+
MessagePackBufferUnpacker unpacker = new MessagePackBufferUnpacker(msgPack);
|
46
|
+
unpacker.wrap(data);
|
47
|
+
return valueToRubyObject(runtime, unpacker.readValue());
|
48
|
+
}
|
49
|
+
|
50
|
+
IRubyObject valueToRubyObject(Ruby runtime, Value value) {
|
51
|
+
switch (value.getType()) {
|
52
|
+
case NIL:
|
53
|
+
return runtime.getNil();
|
54
|
+
case BOOLEAN:
|
55
|
+
return convert(runtime, value.asBooleanValue());
|
56
|
+
case INTEGER:
|
57
|
+
return convert(runtime, value.asIntegerValue());
|
58
|
+
case FLOAT:
|
59
|
+
return convert(runtime, value.asFloatValue());
|
60
|
+
case ARRAY:
|
61
|
+
return convert(runtime, value.asArrayValue());
|
62
|
+
case MAP:
|
63
|
+
return convert(runtime, value.asMapValue());
|
64
|
+
case RAW:
|
65
|
+
return convert(runtime, value.asRawValue());
|
66
|
+
default:
|
67
|
+
throw runtime.newArgumentError(String.format("Unexpected value: %s", value.toString()));
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
private IRubyObject convert(Ruby runtime, BooleanValue value) {
|
72
|
+
return RubyBoolean.newBoolean(runtime, value.asBooleanValue().getBoolean());
|
73
|
+
}
|
74
|
+
|
75
|
+
private IRubyObject convert(Ruby runtime, IntegerValue value) {
|
76
|
+
// TODO: is there any way of checking for bignums up front?
|
77
|
+
IntegerValue iv = value.asIntegerValue();
|
78
|
+
try {
|
79
|
+
return RubyFixnum.newFixnum(runtime, iv.getLong());
|
80
|
+
} catch (MessageTypeException mte) {
|
81
|
+
return RubyBignum.newBignum(runtime, iv.getBigInteger());
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
private IRubyObject convert(Ruby runtime, FloatValue value) {
|
86
|
+
return RubyFloat.newFloat(runtime, value.asFloatValue().getDouble());
|
87
|
+
}
|
88
|
+
|
89
|
+
private IRubyObject convert(Ruby runtime, ArrayValue value) {
|
90
|
+
Value[] elements = value.asArrayValue().getElementArray();
|
91
|
+
int elementCount = elements.length;
|
92
|
+
IRubyObject[] rubyObjects = new IRubyObject[elementCount];
|
93
|
+
for (int i = 0; i < elementCount; i++) {
|
94
|
+
rubyObjects[i] = valueToRubyObject(runtime, elements[i]);
|
95
|
+
}
|
96
|
+
return RubyArray.newArray(runtime, rubyObjects);
|
97
|
+
}
|
98
|
+
|
99
|
+
private IRubyObject convert(Ruby runtime, MapValue value) {
|
100
|
+
Value[] keysAndValues = value.asMapValue().getKeyValueArray();
|
101
|
+
int kvCount = keysAndValues.length;
|
102
|
+
RubyHash hash = RubyHash.newHash(runtime);
|
103
|
+
for (int i = 0; i < kvCount; i += 2) {
|
104
|
+
Value k = keysAndValues[i];
|
105
|
+
Value v = keysAndValues[i + 1];
|
106
|
+
hash.put(valueToRubyObject(runtime, k), valueToRubyObject(runtime, v));
|
107
|
+
}
|
108
|
+
return hash;
|
109
|
+
}
|
110
|
+
|
111
|
+
private IRubyObject convert(Ruby runtime, RawValue value) {
|
112
|
+
return RubyString.newString(runtime, value.asRawValue().getByteArray());
|
113
|
+
}
|
114
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
data/lib/msgpack/version.rb
CHANGED
data/lib/msgpack.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
$CLASSPATH << File.expand_path('../ext', __FILE__) << File.expand_path('../ext/msgpack-0.5.2-devel.jar', __FILE__)
|
3
|
+
$: << File.expand_path('../ext', __FILE__)
|
6
4
|
|
7
|
-
|
5
|
+
require 'java'
|
6
|
+
require 'javassist-3.15.0-GA'
|
7
|
+
require 'msgpack-0.6.6'
|
8
|
+
require 'msgpack_jruby'
|
data/spec/benchmark.rb
CHANGED
@@ -10,17 +10,23 @@ require 'msgpack'
|
|
10
10
|
require 'json'
|
11
11
|
require 'bson'
|
12
12
|
|
13
|
+
if RUBY_PLATFORM.include?('java')
|
14
|
+
BSON_IMPL = BSON::BSON_JAVA
|
15
|
+
else
|
16
|
+
BSON_IMPL = BSON::BSON_C
|
17
|
+
end
|
13
18
|
|
14
19
|
OBJECT_STRUCTURE = {'x' => ['y', 34, 2**30 + 3, 2.1223423423356, {'hello' => 'world', '5' => [63, 'asjdl']}]}
|
15
20
|
ENCODED_MSGPACK = "\x81\xA1x\x95\xA1y\"\xCE@\x00\x00\x03\xCB@\x00\xFA\x8E\x9F9\xFA\xC1\x82\xA5hello\xA5world\xA15\x92?\xA5asjdl"
|
16
21
|
ENCODED_BSON = "d\x00\x00\x00\x04x\x00\\\x00\x00\x00\x020\x00\x02\x00\x00\x00y\x00\x101\x00\"\x00\x00\x00\x102\x00\x03\x00\x00@\x013\x00\xC1\xFA9\x9F\x8E\xFA\x00@\x034\x002\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x045\x00\x19\x00\x00\x00\x100\x00?\x00\x00\x00\x021\x00\x06\x00\x00\x00asjdl\x00\x00\x00\x00\x00"
|
17
22
|
ENCODED_JSON = '{"x":["y",34,1073741827,2.1223423423356,{"hello":"world","5":[63,"asjdl"]}]}'
|
18
23
|
ITERATIONS = 1_00_000
|
24
|
+
IMPLEMENTATIONS = ENV.fetch('IMPLEMENTATIONS', 'json,bson,msgpack').split(',').map(&:to_sym)
|
19
25
|
|
20
26
|
Viiite.bm do |b|
|
21
27
|
b.variation_point :ruby, Viiite.which_ruby
|
22
28
|
|
23
|
-
|
29
|
+
IMPLEMENTATIONS.each do |lib|
|
24
30
|
b.variation_point :lib, lib
|
25
31
|
|
26
32
|
|
@@ -28,7 +34,7 @@ Viiite.bm do |b|
|
|
28
34
|
ITERATIONS.times do
|
29
35
|
case lib
|
30
36
|
when :msgpack then MessagePack.pack(OBJECT_STRUCTURE)
|
31
|
-
when :bson then
|
37
|
+
when :bson then BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s
|
32
38
|
when :json then OBJECT_STRUCTURE.to_json
|
33
39
|
end
|
34
40
|
end
|
@@ -38,7 +44,7 @@ Viiite.bm do |b|
|
|
38
44
|
ITERATIONS.times do
|
39
45
|
case lib
|
40
46
|
when :msgpack then MessagePack.unpack(ENCODED_MSGPACK)
|
41
|
-
when :bson then
|
47
|
+
when :bson then BSON_IMPL.deserialize(ENCODED_BSON)
|
42
48
|
when :json then JSON.parse(ENCODED_JSON)
|
43
49
|
end
|
44
50
|
end
|
@@ -48,7 +54,7 @@ Viiite.bm do |b|
|
|
48
54
|
ITERATIONS.times do
|
49
55
|
case lib
|
50
56
|
when :msgpack then MessagePack.unpack(MessagePack.pack(OBJECT_STRUCTURE))
|
51
|
-
when :bson then
|
57
|
+
when :bson then BSON_IMPL.deserialize(BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s)
|
52
58
|
when :json then JSON.parse(OBJECT_STRUCTURE.to_json)
|
53
59
|
end
|
54
60
|
end
|
@@ -58,7 +64,7 @@ Viiite.bm do |b|
|
|
58
64
|
ITERATIONS.times do
|
59
65
|
case lib
|
60
66
|
when :msgpack then MessagePack.pack(MessagePack.unpack(ENCODED_MSGPACK))
|
61
|
-
when :bson then
|
67
|
+
when :bson then BSON_IMPL.serialize(BSON_IMPL.deserialize(ENCODED_BSON)).to_s
|
62
68
|
when :json then OBJECT_STRUCTURE.to_json(JSON.parse(ENCODED_JSON))
|
63
69
|
end
|
64
70
|
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
require 'stringio'
|
5
|
+
require 'tempfile'
|
6
|
+
|
7
|
+
|
8
|
+
describe ::MessagePack::Unpacker do
|
9
|
+
subject do
|
10
|
+
described_class.new
|
11
|
+
end
|
12
|
+
|
13
|
+
let :buffer1 do
|
14
|
+
MessagePack.pack(:foo => 'bar')
|
15
|
+
end
|
16
|
+
|
17
|
+
let :buffer2 do
|
18
|
+
MessagePack.pack(:hello => {:world => [1, 2, 3]})
|
19
|
+
end
|
20
|
+
|
21
|
+
let :buffer3 do
|
22
|
+
MessagePack.pack(:x => 'y')
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#execute/#execute_limit/#finished?' do
|
26
|
+
let :buffer do
|
27
|
+
buffer1 + buffer2 + buffer3
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'extracts an object from the buffer' do
|
31
|
+
subject.execute(buffer, 0)
|
32
|
+
subject.data.should == {'foo' => 'bar'}
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'extracts an object from the buffer, starting at an offset' do
|
36
|
+
subject.execute(buffer, buffer1.length)
|
37
|
+
subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'extracts an object from the buffer, starting at an offset reading bytes up to a limit' do
|
41
|
+
subject.execute_limit(buffer, buffer1.length, buffer2.length)
|
42
|
+
subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'extracts nothing if the limit cuts an object in half' do
|
46
|
+
subject.execute_limit(buffer, buffer1.length, 3)
|
47
|
+
subject.data.should be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns the offset where the object ended' do
|
51
|
+
subject.execute(buffer, 0).should == buffer1.length
|
52
|
+
subject.execute(buffer, buffer1.length).should == buffer1.length + buffer2.length
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'is finished if #data returns an object' do
|
56
|
+
subject.execute_limit(buffer, buffer1.length, buffer2.length)
|
57
|
+
subject.should be_finished
|
58
|
+
|
59
|
+
subject.execute_limit(buffer, buffer1.length, 3)
|
60
|
+
subject.should_not be_finished
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#each' do
|
65
|
+
context 'with a buffer' do
|
66
|
+
it 'yields each object in the buffer' do
|
67
|
+
objects = []
|
68
|
+
subject.feed(buffer1)
|
69
|
+
subject.feed(buffer2)
|
70
|
+
subject.feed(buffer3)
|
71
|
+
subject.each do |obj|
|
72
|
+
objects << obj
|
73
|
+
end
|
74
|
+
objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns an enumerator when no block is given' do
|
78
|
+
subject.feed(buffer1)
|
79
|
+
subject.feed(buffer2)
|
80
|
+
subject.feed(buffer3)
|
81
|
+
enum = subject.each
|
82
|
+
enum.map { |obj| obj.keys.first }.should == %w[foo hello x]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'with a StringIO stream' do
|
87
|
+
it 'yields each object in the stream' do
|
88
|
+
objects = []
|
89
|
+
subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
|
90
|
+
subject.each do |obj|
|
91
|
+
objects << obj
|
92
|
+
end
|
93
|
+
objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'with a File stream' do
|
98
|
+
it 'yields each object in the stream' do
|
99
|
+
objects = []
|
100
|
+
file = Tempfile.new('msgpack')
|
101
|
+
file.write(buffer1)
|
102
|
+
file.write(buffer2)
|
103
|
+
file.write(buffer3)
|
104
|
+
file.open
|
105
|
+
subject.stream = file
|
106
|
+
subject.each do |obj|
|
107
|
+
objects << obj
|
108
|
+
end
|
109
|
+
objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'with a stream passed to the constructor' do
|
114
|
+
it 'yields each object in the stream' do
|
115
|
+
objects = []
|
116
|
+
unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3))
|
117
|
+
unpacker.each do |obj|
|
118
|
+
objects << obj
|
119
|
+
end
|
120
|
+
objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#feed_each' do
|
126
|
+
it 'feeds the buffer then runs #each' do
|
127
|
+
objects = []
|
128
|
+
subject.feed_each(buffer1 + buffer2 + buffer3) do |obj|
|
129
|
+
objects << obj
|
130
|
+
end
|
131
|
+
objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '#fill' do
|
136
|
+
it 'is a no-op' do
|
137
|
+
subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
|
138
|
+
subject.fill
|
139
|
+
subject.each { |obj| }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '#reset' do
|
144
|
+
context 'with a buffer' do
|
145
|
+
it 'is unclear what it is supposed to do'
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'with a stream' do
|
149
|
+
it 'is unclear what it is supposed to do'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'regressions' do
|
154
|
+
it 'handles massive arrays (issue #2)' do
|
155
|
+
array = ['foo'] * 10_000
|
156
|
+
MessagePack.unpack(MessagePack.pack(array)).should have(10_000).items
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/spec/msgpack_spec.rb
CHANGED
@@ -69,8 +69,13 @@ describe MessagePack do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
context 'with other things' do
|
72
|
-
it 'raises an error on #pack' do
|
72
|
+
it 'raises an error on #pack with an unsupported type' do
|
73
73
|
expect { MessagePack.pack(self) }.to raise_error(ArgumentError, /^Cannot pack type:/)
|
74
74
|
end
|
75
|
+
|
76
|
+
it 'rasies an error on #unpack with garbage' do
|
77
|
+
pending
|
78
|
+
expect { MessagePack.unpack('asdka;sd') }.to raise_error(MessagePack::UnpackError)
|
79
|
+
end
|
75
80
|
end
|
76
81
|
end
|
metadata
CHANGED
@@ -1,76 +1,70 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: msgpack-jruby
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
version: 1.0.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 1.1.3
|
10
6
|
platform: java
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Theo Hultberg
|
13
|
-
autorequire:
|
9
|
+
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
date: 2011-09-15 00:00:00 +02:00
|
18
|
-
default_executable:
|
12
|
+
date: 2012-06-14 00:00:00.000000000Z
|
19
13
|
dependencies: []
|
20
|
-
|
21
14
|
description: JRuby compatible MessagePack implementation that does not use FFI
|
22
|
-
email:
|
15
|
+
email:
|
23
16
|
- theo@iconara.net
|
24
17
|
executables: []
|
25
|
-
|
26
18
|
extensions: []
|
27
|
-
|
28
19
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
files:
|
20
|
+
files:
|
31
21
|
- .gitignore
|
32
22
|
- .rspec
|
33
23
|
- .rvmrc
|
34
24
|
- Gemfile
|
25
|
+
- Gemfile.lock
|
35
26
|
- Rakefile
|
36
|
-
- ext
|
37
|
-
-
|
38
|
-
-
|
27
|
+
- ext/.gitignore
|
28
|
+
- ext/java/MsgpackJrubyService.java
|
29
|
+
- ext/java/org/msgpack/jruby/MessagePackLibrary.java
|
30
|
+
- ext/java/org/msgpack/jruby/RubyObjectPacker.java
|
31
|
+
- ext/java/org/msgpack/jruby/RubyObjectUnpacker.java
|
32
|
+
- lib/ext/javassist-3.15.0-GA.jar
|
33
|
+
- lib/ext/msgpack-0.6.6.jar
|
34
|
+
- lib/ext/msgpack_jruby.jar
|
39
35
|
- lib/msgpack.rb
|
40
36
|
- lib/msgpack/version.rb
|
41
37
|
- msgpack-jruby.gemspec
|
42
38
|
- spec/benchmark.rb
|
39
|
+
- spec/msgpack/unpacker_spec.rb
|
43
40
|
- spec/msgpack_spec.rb
|
44
41
|
- spec/spec_helper.rb
|
45
|
-
has_rdoc: true
|
46
42
|
homepage: http://github.com/iconara/msgpack-jruby
|
47
43
|
licenses: []
|
48
|
-
|
49
|
-
post_install_message:
|
44
|
+
post_install_message:
|
50
45
|
rdoc_options: []
|
51
|
-
|
52
|
-
require_paths:
|
46
|
+
require_paths:
|
53
47
|
- lib
|
54
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
-
requirements:
|
56
|
-
- -
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
segments:
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
segments:
|
59
53
|
- 0
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
version:
|
54
|
+
hash: 2
|
55
|
+
version: '0'
|
56
|
+
none: false
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
none: false
|
68
63
|
requirements: []
|
69
|
-
|
70
64
|
rubyforge_project: msgpack-jruby
|
71
|
-
rubygems_version: 1.
|
72
|
-
signing_key:
|
65
|
+
rubygems_version: 1.8.15
|
66
|
+
signing_key:
|
73
67
|
specification_version: 3
|
74
68
|
summary: MessagePack implementation for JRuby
|
75
69
|
test_files: []
|
76
|
-
|
70
|
+
...
|
@@ -1,156 +0,0 @@
|
|
1
|
-
package org.msgpack.jruby;
|
2
|
-
|
3
|
-
|
4
|
-
import java.io.IOException;
|
5
|
-
import java.io.ByteArrayOutputStream;
|
6
|
-
import java.math.BigInteger;
|
7
|
-
import java.util.Map;
|
8
|
-
import java.util.HashMap;
|
9
|
-
import java.lang.reflect.Field;
|
10
|
-
import org.jruby.runtime.builtin.IRubyObject;
|
11
|
-
import org.jruby.Ruby;
|
12
|
-
import org.jruby.RubyObject;
|
13
|
-
import org.jruby.RubyString;
|
14
|
-
import org.jruby.RubySymbol;
|
15
|
-
import org.jruby.RubyArray;
|
16
|
-
import org.jruby.RubyHash;
|
17
|
-
import org.jruby.RubyBoolean;
|
18
|
-
import org.jruby.RubyInteger;
|
19
|
-
import org.jruby.RubyFixnum;
|
20
|
-
import org.jruby.RubyFloat;
|
21
|
-
import org.jruby.RubyBignum;
|
22
|
-
import org.jruby.RubyNil;
|
23
|
-
import org.msgpack.Packer;
|
24
|
-
import org.msgpack.Unpacker;
|
25
|
-
import org.msgpack.MessagePackObject;
|
26
|
-
import org.msgpack.MessageTypeException;
|
27
|
-
import org.msgpack.object.MapType;
|
28
|
-
|
29
|
-
|
30
|
-
public class MessagePack {
|
31
|
-
private static final MessagePack instance = new MessagePack();
|
32
|
-
|
33
|
-
public static RubyString pack(RubyObject o) throws IOException {
|
34
|
-
return instance.packObject(o);
|
35
|
-
}
|
36
|
-
|
37
|
-
public static RubyObject unpack(RubyString s) throws IOException {
|
38
|
-
return instance.unpackString(s);
|
39
|
-
}
|
40
|
-
|
41
|
-
public RubyString packObject(IRubyObject o) throws IOException {
|
42
|
-
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
43
|
-
_pack(o, new Packer(stream));
|
44
|
-
Ruby runtime = o == null ? Ruby.getGlobalRuntime() : o.getRuntime();
|
45
|
-
return RubyString.newString(runtime, stream.toByteArray());
|
46
|
-
}
|
47
|
-
|
48
|
-
private void _pack(IRubyObject o, Packer packer) throws IOException {
|
49
|
-
if (o == null || o instanceof RubyNil) {
|
50
|
-
packer.packNil();
|
51
|
-
} else if (o instanceof RubyBoolean) {
|
52
|
-
packer.packBoolean((Boolean) ((RubyBoolean) o).toJava(Boolean.class));
|
53
|
-
} else if (o instanceof RubyBignum) {
|
54
|
-
packer.packBigInteger(((RubyBignum) o).getBigIntegerValue());
|
55
|
-
} else if (o instanceof RubyInteger) {
|
56
|
-
packer.packLong(((RubyInteger) o).getLongValue());
|
57
|
-
} else if (o instanceof RubyFixnum) {
|
58
|
-
packer.packLong(((RubyFixnum) o).getLongValue());
|
59
|
-
} else if (o instanceof RubyFloat) {
|
60
|
-
packer.packDouble(((RubyFloat) o).getDoubleValue());
|
61
|
-
} else if (o instanceof RubyString) {
|
62
|
-
byte[] bytes = ((RubyString) o).getBytes();
|
63
|
-
packer.packRaw(bytes.length);
|
64
|
-
packer.packRawBody(bytes);
|
65
|
-
} else if (o instanceof RubySymbol) {
|
66
|
-
_pack((IRubyObject) ((RubySymbol) o).to_s(), packer);
|
67
|
-
} else if (o instanceof RubyArray) {
|
68
|
-
RubyArray array = (RubyArray) o;
|
69
|
-
int count = array.size();
|
70
|
-
packer.packArray(count);
|
71
|
-
for (int i = 0; i < count; i++) {
|
72
|
-
_pack(array.entry(i), packer);
|
73
|
-
}
|
74
|
-
} else if (o instanceof RubyHash) {
|
75
|
-
RubyHash hash = (RubyHash) o;
|
76
|
-
int count = hash.size();
|
77
|
-
packer.packMap(count);
|
78
|
-
RubyArray keys = hash.keys();
|
79
|
-
RubyArray values = hash.rb_values();
|
80
|
-
for (int i = 0; i < count; i++) {
|
81
|
-
_pack(keys.entry(i), packer);
|
82
|
-
_pack(values.entry(i), packer);
|
83
|
-
}
|
84
|
-
} else {
|
85
|
-
throw Ruby.getGlobalRuntime().newArgumentError(String.format("Cannot pack type: %s", o.getClass().getName()));
|
86
|
-
}
|
87
|
-
}
|
88
|
-
|
89
|
-
public RubyObject unpackString(RubyString blob) throws IOException {
|
90
|
-
RubyObject obj = null;
|
91
|
-
Unpacker unpacker = new Unpacker();
|
92
|
-
unpacker.wrap(blob.getBytes());
|
93
|
-
return _unpack(unpacker.iterator().next(), blob.getRuntime());
|
94
|
-
}
|
95
|
-
|
96
|
-
private static Field cachedMapField = null;
|
97
|
-
|
98
|
-
private RubyObject _unpack(MessagePackObject mpo, Ruby runtime) throws IOException {
|
99
|
-
if (mpo.isNil()) {
|
100
|
-
return null;
|
101
|
-
} else if (mpo.isBooleanType()) {
|
102
|
-
return RubyBoolean.newBoolean(runtime, mpo.asBoolean());
|
103
|
-
} else if (mpo.isIntegerType()) {
|
104
|
-
try {
|
105
|
-
return RubyFixnum.newFixnum(runtime, mpo.asLong());
|
106
|
-
} catch (MessageTypeException mte) {
|
107
|
-
return RubyBignum.newBignum(runtime, mpo.asBigInteger());
|
108
|
-
}
|
109
|
-
} else if (mpo.isFloatType()) {
|
110
|
-
return RubyFloat.newFloat(runtime, mpo.asDouble());
|
111
|
-
} else if (mpo.isArrayType()) {
|
112
|
-
MessagePackObject[] mpoElements = mpo.asArray();
|
113
|
-
RubyObject[] elements = new RubyObject[mpoElements.length];
|
114
|
-
int count = mpoElements.length;
|
115
|
-
for (int i = 0; i < count; i++ ) {
|
116
|
-
elements[i] = _unpack(mpoElements[i], runtime);
|
117
|
-
}
|
118
|
-
return RubyArray.newArray(runtime, elements);
|
119
|
-
} else if (mpo.isMapType()) {
|
120
|
-
// This is hackish, but the only way to make sure that hashes
|
121
|
-
// keep their order. MessagePack's unpacking subsystem does not
|
122
|
-
// expose the key/value pair array, only a Map constructed from
|
123
|
-
// that array. This code first attempts to get that array from a
|
124
|
-
// private field, and if that fails it falls back on using the
|
125
|
-
// unordered Map.
|
126
|
-
RubyHash hash = null;
|
127
|
-
try {
|
128
|
-
if (cachedMapField == null) {
|
129
|
-
cachedMapField = mpo.getClass().getDeclaredField("map");
|
130
|
-
cachedMapField.setAccessible(true);
|
131
|
-
}
|
132
|
-
MessagePackObject[] keyValuePairs = (MessagePackObject[]) cachedMapField.get(mpo);
|
133
|
-
int count = keyValuePairs.length;
|
134
|
-
hash = RubyHash.newHash(runtime);
|
135
|
-
for (int i = 0; i < count; i += 2) {
|
136
|
-
hash.put(_unpack(keyValuePairs[i], runtime), _unpack(keyValuePairs[i + 1], runtime));
|
137
|
-
}
|
138
|
-
} catch (IllegalAccessException iae) {
|
139
|
-
} catch (NoSuchFieldException nfe) {
|
140
|
-
}
|
141
|
-
if (hash == null) {
|
142
|
-
Map<MessagePackObject, MessagePackObject> mpoMap = mpo.asMap();
|
143
|
-
hash = RubyHash.newHash(runtime);
|
144
|
-
for (Map.Entry<MessagePackObject, MessagePackObject> entry : mpoMap.entrySet()) {
|
145
|
-
hash.put(_unpack(entry.getKey(), runtime), _unpack(entry.getValue(), runtime));
|
146
|
-
}
|
147
|
-
}
|
148
|
-
return hash;
|
149
|
-
|
150
|
-
} else if (mpo.isRawType()) {
|
151
|
-
return RubyString.newString(runtime, mpo.asByteArray());
|
152
|
-
} else {
|
153
|
-
throw runtime.newArgumentError(String.format("Cannot upack type: %s", mpo.getClass().getName()));
|
154
|
-
}
|
155
|
-
}
|
156
|
-
}
|
Binary file
|
Binary file
|