From 9342e909cf8bba7af8d82dfbb5c8a32dbe6424ec Mon Sep 17 00:00:00 2001 From: Dragos Carp Date: Mon, 17 Jun 2019 12:59:23 +0200 Subject: [PATCH] Fix integer wire format for packed arrays Fix #23 --- src/google/protobuf/decoding.d | 28 ++++++++++++++++++++-------- src/google/protobuf/encoding.d | 14 +++++++++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/google/protobuf/decoding.d b/src/google/protobuf/decoding.d index a085cc8..b0abfc0 100644 --- a/src/google/protobuf/decoding.d +++ b/src/google/protobuf/decoding.d @@ -150,6 +150,21 @@ if (isInputRange!R && isArray!T && !is(T == string) && !is(T == bytes)) return result.data; } +unittest +{ + import std.array : array; + import google.protobuf.encoding : toProtobuf; + + auto buffer = [false, false, true].toProtobuf.array; + assert(buffer.fromProtobuf!(bool[]) == [false, false, true]); + buffer = [1, 2].toProtobuf!(Wire.fixed).array; + assert(buffer.fromProtobuf!(int[], Wire.fixed) == [1, 2]); + buffer = [1, 2].toProtobuf.array; + assert(buffer.fromProtobuf!(int[]) == [1, 2]); + buffer = [-54L, 54L].toProtobuf!(Wire.zigzag).array; + assert(buffer.fromProtobuf!(long[], Wire.zigzag) == [-54L, 54L]); +} + T fromProtobuf(T, R)(ref R inputRange, T result = protoDefaultValue!T) if (isInputRange!R && (is(T == class) || is(T == struct))) { @@ -239,7 +254,7 @@ unittest struct Foo { @Proto(1) int[] bar = protoDefaultValue!(int[]); - @Proto(2, Wire.none, Yes.packed) int[] baz = protoDefaultValue!(int[]); + @Proto(2, Wire.zigzag, Yes.packed) int[] baz = protoDefaultValue!(int[]); } Foo foo; @@ -288,8 +303,7 @@ if (isInputRange!R && isIntegral!T) static assert(is(ElementType!R == ubyte), "Input range should be an ubyte range"); static assert(validateProto!(proto, T)); - enum wire = proto.wire; - field = inputRange.fromProtobuf!(T, wire); + field = inputRange.fromProtobuf!(T, proto.wire); } private void fromProtobufByProto(Proto proto, T, R)(ref R inputRange, ref T field) @@ -298,7 +312,7 @@ if (isInputRange!R && isArray!T && !is(T == string) && !is(T == bytes) && proto. static assert(is(ElementType!R == ubyte), "Input range should be an ubyte range"); static assert(validateProto!(proto, T)); - field ~= inputRange.fromProtobuf!T; + field ~= inputRange.fromProtobuf!(T, proto.wire); } private void fromProtobufByProto(Proto proto, T, R)(ref R inputRange, ref T field) @@ -346,8 +360,7 @@ if (isInputRange!R && isAssociativeArray!T) { static assert(isIntegral!(KeyType!T), "Cannot specify wire format for non-integral map key"); - enum wire = keyProto.wire; - key = fieldRange.fromProtobuf!(KeyType!T, wire); + key = fieldRange.fromProtobuf!(KeyType!T, keyProto.wire); } break; case MapFieldTag.value: @@ -363,8 +376,7 @@ if (isInputRange!R && isAssociativeArray!T) { static assert(isIntegral!(ValueType!T), "Cannot specify wire format for non-integral map value"); - enum wire = valueProto.wire; - value = fieldRange.fromProtobuf!(ValueType!T, wire); + value = fieldRange.fromProtobuf!(ValueType!T, valueProto.wire); } break; default: diff --git a/src/google/protobuf/encoding.d b/src/google/protobuf/encoding.d index 04ac4ce..36bc54b 100644 --- a/src/google/protobuf/encoding.d +++ b/src/google/protobuf/encoding.d @@ -119,6 +119,7 @@ unittest assert([false, false, true].toProtobuf.array == [0x03, 0x00, 0x00, 0x01]); assert([1, 2].toProtobuf!(Wire.fixed).array == [0x08, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]); assert([1, 2].toProtobuf.array == [0x02, 0x01, 0x02]); + assert([-54L, 54L].toProtobuf!(Wire.zigzag).array == [0x02, 0x6b, 0x6c]); } auto toProtobuf(T)(T value) @@ -213,14 +214,14 @@ unittest struct Foo { @Proto(1) int[] bar = protoDefaultValue!(int[]); - @Proto(2, Wire.none, Yes.packed) int[] baz = protoDefaultValue!(int[]); + @Proto(2, Wire.zigzag, Yes.packed) int[] baz = protoDefaultValue!(int[]); } Foo foo; assert(foo.toProtobuf.empty); foo.bar = [1, 2]; foo.baz = [3, 4]; - assert(foo.toProtobuf.array == [0x08, 0x01, 0x08, 0x02, 0x12, 0x02, 0x03, 0x04]); + assert(foo.toProtobuf.array == [0x08, 0x01, 0x08, 0x02, 0x12, 0x02, 0x06, 0x08]); } unittest @@ -322,7 +323,14 @@ if (isBoolean!T || { static assert(validateProto!(proto, T)); - return chain(encodeTag!(proto, T), value.toProtobuf); + static if (proto.wire == Wire.none) + { + return chain(encodeTag!(proto, T), value.toProtobuf); + } + else + { + return chain(encodeTag!(proto, T), value.toProtobuf!(proto.wire)); + } } private auto toProtobufByProto(Proto proto, T)(T value)