diff --git a/src/Chr.Avro.Binary/Serialization/BinaryIntSerializerBuilderCase.cs b/src/Chr.Avro.Binary/Serialization/BinaryIntSerializerBuilderCase.cs index 60a7f85fa..10cd2c7f2 100644 --- a/src/Chr.Avro.Binary/Serialization/BinaryIntSerializerBuilderCase.cs +++ b/src/Chr.Avro.Binary/Serialization/BinaryIntSerializerBuilderCase.cs @@ -19,7 +19,7 @@ public class BinaryIntSerializerBuilderCase : IntSerializerBuilderCase, IBinaryS /// otherwise. /// /// - /// Thrown when cannot be converted to . + /// Thrown when cannot be converted to . /// /// public virtual BinarySerializerBuilderCaseResult BuildExpression(Expression value, Type type, Schema schema, BinarySerializerBuilderContext context) @@ -27,12 +27,12 @@ public virtual BinarySerializerBuilderCaseResult BuildExpression(Expression valu if (schema is IntSchema intSchema) { var writeInteger = typeof(BinaryWriter) - .GetMethod(nameof(BinaryWriter.WriteInteger), new[] { typeof(long) }); + .GetMethod(nameof(BinaryWriter.WriteInteger), new[] { typeof(int) }); try { return BinarySerializerBuilderCaseResult.FromExpression( - Expression.Call(context.Writer, writeInteger, BuildConversion(value, typeof(long)))); + Expression.Call(context.Writer, writeInteger, BuildConversion(value, typeof(int)))); } catch (InvalidOperationException exception) { diff --git a/src/Chr.Avro.Binary/Serialization/BinaryWriter.cs b/src/Chr.Avro.Binary/Serialization/BinaryWriter.cs index a7fe5f1ea..072afe8a0 100644 --- a/src/Chr.Avro.Binary/Serialization/BinaryWriter.cs +++ b/src/Chr.Avro.Binary/Serialization/BinaryWriter.cs @@ -84,6 +84,31 @@ public void WriteFixed(byte[] value) stream.Write(value, 0, value.Length); } + /// + /// Writes a variable-length integer to the current position and advances the writer. + /// + /// + /// An value. + /// + public void WriteInteger(int value) + { + var encoded = (uint)((value << 1) ^ (value >> 31)); + + do + { + var current = encoded & 0x7FU; + encoded >>= 7; + + if (encoded != 0) + { + current |= 0x80U; + } + + stream.WriteByte((byte)current); + } + while (encoded != 0U); + } + /// /// Writes a variable-length integer to the current position and advances the writer. /// diff --git a/src/Chr.Avro.Json/Serialization/JsonIntSerializerBuilderCase.cs b/src/Chr.Avro.Json/Serialization/JsonIntSerializerBuilderCase.cs index 5cfc6d58a..f979aefe7 100644 --- a/src/Chr.Avro.Json/Serialization/JsonIntSerializerBuilderCase.cs +++ b/src/Chr.Avro.Json/Serialization/JsonIntSerializerBuilderCase.cs @@ -20,7 +20,7 @@ public class JsonIntSerializerBuilderCase : IntSerializerBuilderCase, IJsonSeria /// otherwise. /// /// - /// Thrown when cannot be converted to . + /// Thrown when cannot be converted to . /// /// public virtual JsonSerializerBuilderCaseResult BuildExpression(Expression value, Type type, Schema schema, JsonSerializerBuilderContext context) diff --git a/tests/Chr.Avro.Binary.Tests/BinaryWriterTests.cs b/tests/Chr.Avro.Binary.Tests/BinaryWriterTests.cs index 3f29aa805..3b871d87a 100644 --- a/tests/Chr.Avro.Binary.Tests/BinaryWriterTests.cs +++ b/tests/Chr.Avro.Binary.Tests/BinaryWriterTests.cs @@ -54,17 +54,23 @@ public BinaryWriterTests() new object[] { double.PositiveInfinity, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f } }, }; - public static IEnumerable IntegerEncodings => new List + public static IEnumerable Int32Encodings => new List + { + new object[] { 0, new byte[] { 0x00 } }, + new object[] { -1, new byte[] { 0x01 } }, + new object[] { 1, new byte[] { 0x02 } }, + new object[] { -2, new byte[] { 0x03 } }, + new object[] { 2, new byte[] { 0x04 } }, + new object[] { -64, new byte[] { 0x7f } }, + new object[] { 64, new byte[] { 0x80, 0x01 } }, + new object[] { -8192, new byte[] { 0xff, 0x7f } }, + new object[] { 8192, new byte[] { 0x80, 0x80, 0x01 } }, + new object[] { int.MinValue, new byte[] { 0xff, 0xff, 0xff, 0xff, 0x0f } }, + new object[] { int.MaxValue, new byte[] { 0xfe, 0xff, 0xff, 0xff, 0x0f } }, + }; + + public static IEnumerable Int64Encodings => new List { - new object[] { 0L, new byte[] { 0x00 } }, - new object[] { -1L, new byte[] { 0x01 } }, - new object[] { 1L, new byte[] { 0x02 } }, - new object[] { -2L, new byte[] { 0x03 } }, - new object[] { 2L, new byte[] { 0x04 } }, - new object[] { -64L, new byte[] { 0x7f } }, - new object[] { 64L, new byte[] { 0x80, 0x01 } }, - new object[] { -8192L, new byte[] { 0xff, 0x7f } }, - new object[] { 8192L, new byte[] { 0x80, 0x80, 0x01 } }, new object[] { -4611686018427387904L, new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f } }, new object[] { 4611686018427387904L, new byte[] { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01 } }, new object[] { long.MinValue, new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 } }, @@ -108,8 +114,21 @@ public void WritesDoubles(double value, byte[] encoding) } [Theory] - [MemberData(nameof(IntegerEncodings))] - public void WritesIntegers(long value, byte[] encoding) + [MemberData(nameof(Int32Encodings))] + public void WritesInt32s(int value, byte[] encoding) + { + using (stream) + { + writer.WriteInteger(value); + } + + Assert.Equal(encoding, stream.ToArray()); + } + + [Theory] + [MemberData(nameof(Int32Encodings))] + [MemberData(nameof(Int64Encodings))] + public void WritesInt64s(long value, byte[] encoding) { using (stream) { diff --git a/tests/Chr.Avro.Binary.Tests/IntegerSerializationTests.cs b/tests/Chr.Avro.Binary.Tests/IntegerSerializationTests.cs index c18d8afa4..6da3b4835 100644 --- a/tests/Chr.Avro.Binary.Tests/IntegerSerializationTests.cs +++ b/tests/Chr.Avro.Binary.Tests/IntegerSerializationTests.cs @@ -75,7 +75,7 @@ public IntegerSerializationTests() public static IEnumerable UInt32s => new List { new object[] { uint.MinValue }, - new object[] { uint.MaxValue }, + new object[] { uint.MaxValue / 2 }, }; public static IEnumerable UInt64s => new List @@ -296,7 +296,7 @@ public void UInt32Values(uint value) [MemberData(nameof(UInt64s))] public void UInt64Values(ulong value) { - var schema = new IntSchema(); + var schema = new LongSchema(); var deserialize = deserializerBuilder.BuildDelegate(schema); var serialize = serializerBuilder.BuildDelegate(schema);