Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility mode #68

Merged
merged 4 commits into from
Jul 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions ext/java/org/msgpack/jruby/Buffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

@JRubyClass(name="MessagePack::Buffer")
public class Buffer extends RubyObject {
private RubyHash options;
private IRubyObject io;
private ByteBuffer buffer;
private boolean writeMode;
Expand All @@ -46,9 +45,6 @@ public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
if (args[0].respondsTo("read") && args[0].respondsTo("write")) {
this.io = args[0];
}
if (args[args.length - 1] instanceof RubyHash) {
this.options = (RubyHash) args[args.length - 1];
}
}
this.buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE);
this.writeMode = true;
Expand Down
8 changes: 5 additions & 3 deletions ext/java/org/msgpack/jruby/Encoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ public class Encoder {
private final Ruby runtime;
private final Encoding binaryEncoding;
private final Encoding utf8Encoding;
private final boolean compatibilityMode;

private ByteBuffer buffer;

public Encoder(Ruby runtime) {
public Encoder(Ruby runtime, boolean compatibilityMode) {
this.runtime = runtime;
this.buffer = ByteBuffer.allocate(CACHE_LINE_SIZE - ARRAY_HEADER_SIZE);
this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
this.utf8Encoding = UTF8Encoding.INSTANCE;
this.compatibilityMode = compatibilityMode;
}

private void ensureRemainingCapacity(int c) {
Expand Down Expand Up @@ -190,7 +192,7 @@ private void appendFloat(RubyFloat object) {

private void appendString(RubyString object) {
Encoding encoding = object.getEncoding();
boolean binary = encoding == binaryEncoding;
boolean binary = !compatibilityMode && encoding == binaryEncoding;
if (encoding != utf8Encoding && encoding != binaryEncoding) {
object = (RubyString) ((RubyString) object).encode(runtime.getCurrentContext(), runtime.getEncodingService().getEncoding(utf8Encoding));
}
Expand All @@ -199,7 +201,7 @@ private void appendString(RubyString object) {
if (length < 32 && !binary) {
ensureRemainingCapacity(1 + length);
buffer.put((byte) (length | FIXSTR));
} else if (length <= 0xff) {
} else if (length <= 0xff && !compatibilityMode) {
ensureRemainingCapacity(2 + length);
buffer.put(binary ? BIN8 : STR8);
buffer.put((byte) length);
Expand Down
7 changes: 6 additions & 1 deletion ext/java/org/msgpack/jruby/Packer.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ public IRubyObject allocate(Ruby runtime, RubyClass type) {

@JRubyMethod(name = "initialize", optional = 2)
public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
this.encoder = new Encoder(ctx.getRuntime());
boolean compatibilityMode = false;
if (args.length > 0 && args[args.length - 1] instanceof RubyHash) {
RubyHash options = (RubyHash) args[args.length - 1];
compatibilityMode = options.fastARef(ctx.getRuntime().newSymbol("compatibility_mode")).isTrue();
}
this.encoder = new Encoder(ctx.getRuntime(), compatibilityMode);
this.buffer = new Buffer(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Buffer"));
this.buffer.initialize(ctx, args);
return this;
Expand Down
5 changes: 3 additions & 2 deletions ext/msgpack/packer.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct msgpack_packer_t {

VALUE io;
ID io_write_all_method;
bool compatibility_mode;

ID to_msgpack_method;
VALUE to_msgpack_arg;
Expand Down Expand Up @@ -270,7 +271,7 @@ static inline void msgpack_packer_write_raw_header(msgpack_packer_t* pk, unsigne
msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 1);
unsigned char h = 0xa0 | (uint8_t) n;
msgpack_buffer_write_1(PACKER_BUFFER_(pk), h);
} else if(n < 256) {
} else if(n < 256 && !pk->compatibility_mode) {
msgpack_buffer_ensure_writable(PACKER_BUFFER_(pk), 2);
unsigned char be = (uint8_t) n;
msgpack_buffer_write_byte_and_data(PACKER_BUFFER_(pk), 0xd9, (const void*)&be, 1);
Expand Down Expand Up @@ -368,7 +369,7 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE

#ifdef COMPAT_HAVE_ENCODING
int encindex = ENCODING_GET(v);
if(msgpack_packer_is_binary(v, encindex)) {
if(msgpack_packer_is_binary(v, encindex) && !pk->compatibility_mode) {
/* write ASCII-8BIT string using Binary type */
msgpack_packer_write_bin_header(pk, (unsigned int)len);
msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
Expand Down
5 changes: 5 additions & 0 deletions ext/msgpack/packer_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ VALUE MessagePack_pack(int argc, VALUE* argv)

VALUE self = Packer_alloc(cMessagePack_Packer);
PACKER(self, pk);

if (options != Qnil) {
pk->compatibility_mode = RTEST(rb_hash_aref(options, ID2SYM(rb_intern("compatibility_mode"))));
}

//msgpack_packer_reset(s_packer);
//msgpack_buffer_reset_io(PACKER_BUFFER_(s_packer));

Expand Down
14 changes: 14 additions & 0 deletions spec/cruby/packer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,19 @@ def to_msgpack(pk=nil)
CustomPack02.new.to_msgpack(s04)
s04.string.should == [1,2].to_msgpack
end

context 'in compatibility mode' do
it 'does not use the bin types' do
packed = MessagePack.pack('hello'.force_encoding(Encoding::BINARY), compatibility_mode: true)
packed.should eq("\xA5hello")
packed = MessagePack.pack(('hello' * 100).force_encoding(Encoding::BINARY), compatibility_mode: true)
packed.should start_with("\xDA\x01\xF4")
end

it 'does not use the str8 type' do
packed = MessagePack.pack('x' * 32, compatibility_mode: true)
packed.should start_with("\xDA\x00\x20")
end
end
end

22 changes: 21 additions & 1 deletion spec/jruby/msgpack_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,15 @@ def asciienc(str)
['negative floats', -2.1, "\xCB\xC0\x00\xCC\xCC\xCC\xCC\xCC\xCD"]
],
'strings' => [
['strings', utf8enc('hello world'), "\xABhello world"],
['tiny strings', utf8enc('hello world'), "\xABhello world"],
['short strings', utf8enc('hello' * 5), "\xB9hellohellohellohellohello"],
['empty strings', utf8enc(''), "\xA0"]
],
'binary strings' => [
['tiny strings', asciienc('hello world'), "\xC4\vhello world"],
['short strings', asciienc('hello' * 5), "\xC4\x19hellohellohellohellohello"],
['empty strings', asciienc(''), "\xC4\x00"]
],
'arrays' => [
['empty arrays', [], "\x90"],
['arrays with strings', [utf8enc("hello"), utf8enc("world")], "\x92\xA5hello\xA5world"],
Expand Down Expand Up @@ -139,4 +145,18 @@ def asciienc(str)
packed.index("w\xC3\xA5rld").should_not be_nil
end
end

context 'in compatibility mode' do
it 'does not use the bin types' do
packed = MessagePack.pack('hello'.force_encoding(Encoding::BINARY), compatibility_mode: true)
packed.should eq("\xA5hello")
packed = MessagePack.pack(('hello' * 100).force_encoding(Encoding::BINARY), compatibility_mode: true)
packed.should start_with("\xDA\x01\xF4")
end

it 'does not use the str8 type' do
packed = MessagePack.pack('x' * 32, compatibility_mode: true)
packed.should start_with("\xDA\x00\x20")
end
end
end