diff --git a/code-generator/src/main/java/io/streamnative/lightproto/generator/LightProtoNumberField.java b/code-generator/src/main/java/io/streamnative/lightproto/generator/LightProtoNumberField.java index c297299..31ad40c 100644 --- a/code-generator/src/main/java/io/streamnative/lightproto/generator/LightProtoNumberField.java +++ b/code-generator/src/main/java/io/streamnative/lightproto/generator/LightProtoNumberField.java @@ -55,8 +55,10 @@ static void serializeNumber(PrintWriter w, ProtoFieldDescriptor field, String na } else if (field.getProtoType().equals("bool")) { writer = "writeRawByte"; value = name + " ? 1 : 0"; - } else if (field.getProtoType().equals("int32") || field.getProtoType().equals("uint32")) { + } else if (field.getProtoType().equals("int32")) { writer = "writeRawVarInt"; + } else if (field.getProtoType().equals("uint32")) { + writer = "writeRawVarUInt"; } else if (field.getProtoType().equals("sint32")) { writer = "writeRawSignedVarInt"; } else if (field.getProtoType().equals("sint64")) { @@ -140,7 +142,7 @@ static String serializedSizeOfNumber(ProtoFieldDescriptor field, String name) { } else if (field.getProtoType().equals("int32")) { return String.format("LightProtoCodec.computeVarIntSize(%s)", name); } else if (field.getProtoType().equals("uint32")) { - return String.format("LightProtoCodec.computeVarIntSize(%s)", name); + return String.format("LightProtoCodec.computeVarUIntSize(%s)", name); } else if (field.getProtoType().equals("int64")) { return String.format("LightProtoCodec.computeVarInt64Size(%s)", name); } else if (field.getProtoType().equals("uint64")) { diff --git a/code-generator/src/main/resources/io/streamnative/lightproto/generator/LightProtoCodec.java b/code-generator/src/main/resources/io/streamnative/lightproto/generator/LightProtoCodec.java index 619030a..c4ddb0e 100644 --- a/code-generator/src/main/resources/io/streamnative/lightproto/generator/LightProtoCodec.java +++ b/code-generator/src/main/resources/io/streamnative/lightproto/generator/LightProtoCodec.java @@ -427,7 +427,7 @@ static int writeRawVarInt64(byte[] a, int i, long value) { /** * Writes n as an unsigned 32-bit varint, at most 5 bytes, as protobuf encodes - * zigzag-encoded sint32 values: what computeVarUIntSize() counts. + * uint32 and zigzag-encoded sint32 values: what computeVarUIntSize() counts. * writeRawVarInt() is the int32 encoding, which writes a negative n as 10 bytes. */ static int writeRawVarUInt(byte[] a, int i, int n) { diff --git a/tests/src/test/java/io/streamnative/lightproto/tests/NumbersTest.java b/tests/src/test/java/io/streamnative/lightproto/tests/NumbersTest.java index e130f4d..c2f6522 100644 --- a/tests/src/test/java/io/streamnative/lightproto/tests/NumbersTest.java +++ b/tests/src/test/java/io/streamnative/lightproto/tests/NumbersTest.java @@ -206,6 +206,13 @@ public void testNumberFields() throws Exception { verify(lpn, pbn.build()); } + @ParameterizedTest + @ValueSource(ints = {Integer.MIN_VALUE, -1}) + public void testUint32AboveIntMax(int value) throws Exception { + // 2^31 and 2^32 - 1: protobuf writes a uint32 as an unsigned varint, 5 bytes + verify(new Numbers().setXUint32(value), NumbersOuterClass.Numbers.newBuilder().setXUint32(value).build()); + } + @ParameterizedTest @ValueSource(ints = {1 << 30, -(1 << 30) - 1, Integer.MAX_VALUE, Integer.MIN_VALUE}) public void testSint32WithZigZagTopBitSet(int value) throws Exception { diff --git a/tests/src/test/java/io/streamnative/lightproto/tests/RepeatedNumbersTest.java b/tests/src/test/java/io/streamnative/lightproto/tests/RepeatedNumbersTest.java index 08d8ff0..1495be6 100644 --- a/tests/src/test/java/io/streamnative/lightproto/tests/RepeatedNumbersTest.java +++ b/tests/src/test/java/io/streamnative/lightproto/tests/RepeatedNumbersTest.java @@ -503,4 +503,22 @@ public void testSint32WithZigZagTopBitSet() throws Exception { assertArrayEquals(pb.build().toByteArray(), lp.toByteArray()); assertArrayEquals(pbPacked.build().toByteArray(), lpPacked.toByteArray()); } + + @Test + public void testUint32AboveIntMax() throws Exception { + // 2^31 and 2^32 - 1: protobuf writes a uint32 as an unsigned varint, 5 bytes + int[] values = {Integer.MIN_VALUE, -1}; + Repeated lp = new Repeated(); + RepeatedPacked lpPacked = new RepeatedPacked(); + RepeatedNumbers.Repeated.Builder pb = RepeatedNumbers.Repeated.newBuilder(); + RepeatedNumbers.RepeatedPacked.Builder pbPacked = RepeatedNumbers.RepeatedPacked.newBuilder(); + for (int value : values) { + lp.addXUint32(value); + lpPacked.addXUint32(value); + pb.addXUint32(value); + pbPacked.addXUint32(value); + } + assertArrayEquals(pb.build().toByteArray(), lp.toByteArray()); + assertArrayEquals(pbPacked.build().toByteArray(), lpPacked.toByteArray()); + } }