This is an automated email from the ASF dual-hosted git repository. mgrigorov pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/avro-rs.git
commit e3bce531246d84afec334c89a3d6e1c61d57356d Author: Kriskras99 <[email protected]> AuthorDate: Wed Nov 12 13:48:41 2025 +0100 fix: Make zigzag varint encoding and decoding endianness agnostic --- avro/src/util.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/avro/src/util.rs b/avro/src/util.rs index 1c986f4..ba319d3 100644 --- a/avro/src/util.rs +++ b/avro/src/util.rs @@ -78,19 +78,24 @@ pub(crate) fn read_long<R: Read>(reader: &mut R) -> AvroResult<i64> { zag_i64(reader) } +/// Write the number as a zigzagged varint to the writer. pub(crate) fn zig_i32<W: Write>(n: i32, buffer: W) -> AvroResult<usize> { zig_i64(n as i64, buffer) } +/// Write the number as a zigzagged varint to the writer. pub(crate) fn zig_i64<W: Write>(n: i64, writer: W) -> AvroResult<usize> { - encode_variable(((n << 1) ^ (n >> 63)) as u64, writer) + let zigzagged = ((n << 1) ^ (n >> 63)) as u64; + encode_variable(zigzagged, writer) } +/// Decode a zigzagged varint from the reader. pub(crate) fn zag_i32<R: Read>(reader: &mut R) -> AvroResult<i32> { let i = zag_i64(reader)?; i32::try_from(i).map_err(|e| Details::ZagI32(e, i).into()) } +/// Decode a zigzagged varint from the reader. pub(crate) fn zag_i64<R: Read>(reader: &mut R) -> AvroResult<i64> { let z = decode_variable(reader)?; Ok(if z & 0x1 == 0 { @@ -100,18 +105,24 @@ pub(crate) fn zag_i64<R: Read>(reader: &mut R) -> AvroResult<i64> { }) } -fn encode_variable<W: Write>(mut z: u64, mut writer: W) -> AvroResult<usize> { +/// Write the number as a varint to the writer. +/// +/// Note: this function does not do zigzag encoding, for that see [`zig_i32`] and [`zig_i64`]. +fn encode_variable<W: Write>(mut zigzagged: u64, mut writer: W) -> AvroResult<usize> { + // Ensure the number is little endian for the varint encoding (no-op on LE systems) + zigzagged = zigzagged.to_le(); + // Encode the number as a varint let mut buffer = [0u8; 10]; let mut i: usize = 0; loop { - if z <= 0x7F { - buffer[i] = (z & 0x7F) as u8; + if zigzagged <= 0x7F { + buffer[i] = (zigzagged & 0x7F) as u8; i += 1; break; } else { - buffer[i] = (0x80 | (z & 0x7F)) as u8; + buffer[i] = (0x80 | (zigzagged & 0x7F)) as u8; i += 1; - z >>= 7; + zigzagged >>= 7; } } writer @@ -119,6 +130,9 @@ fn encode_variable<W: Write>(mut z: u64, mut writer: W) -> AvroResult<usize> { .map_err(|e| Details::WriteBytes(e).into()) } +/// Read a varint from the reader. +/// +/// Note: this function does not do zigzag decoding, for that see [`zag_i32`] and [`zag_i64`]. fn decode_variable<R: Read>(reader: &mut R) -> AvroResult<u64> { let mut i = 0u64; let mut buf = [0u8; 1]; @@ -140,7 +154,7 @@ fn decode_variable<R: Read>(reader: &mut R) -> AvroResult<u64> { } } - Ok(i) + Ok(u64::from_le(i)) } /// Set the maximum number of bytes that can be allocated when decoding data.
