From 739bc504f101dd57a8b917f7865352ca6dc2e41a Mon Sep 17 00:00:00 2001 From: Kriskras99 Date: Sun, 6 Sep 2026 15:22:34 +0200 Subject: [PATCH 1/3] feat: Optimize UUID decoding in `decode.rs` This way we don't have to do any allocations or check that the bytes are valid UTF-8. --- avro/src/decode.rs | 66 ++++++++++++++++++++++------------------------ avro/src/error.rs | 6 +++++ 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/avro/src/decode.rs b/avro/src/decode.rs index 24d61d20..56794dd0 100644 --- a/avro/src/decode.rs +++ b/avro/src/decode.rs @@ -216,46 +216,42 @@ fn decode_internal_body>( } } Schema::Uuid(UuidSchema::String) => { - let Value::String(string) = - decode_internal(&Schema::String, names, enclosing_namespace, reader, ctx)? - else { - // decoding a String can also return a Null, indicating EOF - return Err(Error::new(Details::ReadBytes(std::io::Error::from( - ErrorKind::UnexpectedEof, - )))); - }; - let uuid = Uuid::parse_str(&string).map_err(Details::ConvertStrToUuid)?; - Ok(Value::Uuid(uuid)) + let len = decode_len(reader)?; + if len <= uuid::fmt::Urn::LENGTH { + let mut buf = [0u8; uuid::fmt::Urn::LENGTH]; + reader + .read_exact(&mut buf[..len]) + .map_err(Details::ReadString)?; + let uuid = Uuid::try_parse_ascii(&buf[..len]).map_err(Details::ConvertStrToUuid)?; + Ok(Value::Uuid(uuid)) + } else { + Err(Details::ConvertStringToUuid(uuid::fmt::Urn::LENGTH, len).into()) + } } Schema::Uuid(UuidSchema::Bytes) => { - let Value::Bytes(bytes) = - decode_internal(&Schema::Bytes, names, enclosing_namespace, reader, ctx)? - else { - unreachable!( - "decode_internal(Schema::Bytes) can only return a Value::Bytes or an error" - ) - }; - let uuid = Uuid::from_slice(&bytes).map_err(Details::ConvertSliceToUuid)?; - Ok(Value::Uuid(uuid)) + let len = decode_len(reader)?; + if len == 16 { + let mut buf = [0u8; 16]; + reader + .read_exact(&mut buf) + .map_err(|e| Details::ReadFixed(e, 16))?; + let uuid = Uuid::from_slice(&buf).map_err(Details::ConvertSliceToUuid)?; + Ok(Value::Uuid(uuid)) + } else { + Err(Details::ConvertBytesToUuid(len).into()) + } } Schema::Uuid(UuidSchema::Fixed(fixed)) => { - let Value::Fixed(n, bytes) = decode_internal( - &Schema::Fixed(fixed.copy_only_size()), - names, - enclosing_namespace, - reader, - ctx, - )? - else { - unreachable!( - "decode_internal(Schema::Fixed) can only return a Value::Fixed or an error" - ) - }; - if n != 16 { - return Err(Details::ConvertFixedToUuid(n).into()); + if fixed.size == 16 { + let mut buf = [0u8; 16]; + reader + .read_exact(&mut buf) + .map_err(|e| Details::ReadFixed(e, 16))?; + let uuid = Uuid::from_slice(&buf).map_err(Details::ConvertSliceToUuid)?; + Ok(Value::Uuid(uuid)) + } else { + Err(Details::ConvertFixedToUuid(fixed.size).into()) } - let uuid = Uuid::from_slice(&bytes).map_err(Details::ConvertSliceToUuid)?; - Ok(Value::Uuid(uuid)) } Schema::Int => decode_int(reader), Schema::Date => zag_i32(reader).map(Value::Date), diff --git a/avro/src/error.rs b/avro/src/error.rs index 0c059134..58f9145f 100644 --- a/avro/src/error.rs +++ b/avro/src/error.rs @@ -156,6 +156,12 @@ pub enum Details { #[error("Failed to convert Fixed bytes to UUID. It must be exactly 16 bytes, got {0}")] ConvertFixedToUuid(usize), + #[error("Failed to convert Bytes to UUID. It must be exactly 16 bytes, got {0}")] + ConvertBytesToUuid(usize), + + #[error("Failed to convert String to UUID. Expected at most {0} bytes, got {0}")] + ConvertStringToUuid(usize, usize), + #[error("Failed to convert Fixed bytes to UUID: {0}")] ConvertSliceToUuid(#[source] uuid::Error), From a066cd00a6d353076a68364749ebbf45f9e13865 Mon Sep 17 00:00:00 2001 From: Kriskras99 Date: Mon, 7 Sep 2026 20:53:01 +0200 Subject: [PATCH 2/3] fix: Wrong error message --- avro/src/decode.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/avro/src/decode.rs b/avro/src/decode.rs index 56794dd0..8bff4fc2 100644 --- a/avro/src/decode.rs +++ b/avro/src/decode.rs @@ -232,9 +232,7 @@ fn decode_internal_body>( let len = decode_len(reader)?; if len == 16 { let mut buf = [0u8; 16]; - reader - .read_exact(&mut buf) - .map_err(|e| Details::ReadFixed(e, 16))?; + reader.read_exact(&mut buf).map_err(Details::ReadBytes)?; let uuid = Uuid::from_slice(&buf).map_err(Details::ConvertSliceToUuid)?; Ok(Value::Uuid(uuid)) } else { From aba17de0c3686490890c4f0cdd628dea6d86f4bc Mon Sep 17 00:00:00 2001 From: Kriskras99 Date: Mon, 7 Sep 2026 22:17:51 +0200 Subject: [PATCH 3/3] fix: Leftover imports after rebase --- avro/src/decode.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/avro/src/decode.rs b/avro/src/decode.rs index 8bff4fc2..00b8b67c 100644 --- a/avro/src/decode.rs +++ b/avro/src/decode.rs @@ -17,7 +17,7 @@ use crate::schema::{InnerDecimalSchema, NamespaceRef, UuidSchema}; use crate::{ - AvroResult, Error, + AvroResult, bigdecimal::deserialize_big_decimal, decimal::Decimal, duration::Duration, @@ -29,11 +29,7 @@ use crate::{ safe_collection_len, safe_len, zag_i32, zag_i64, }, }; -use std::{ - borrow::Borrow, - collections::HashMap, - io::{ErrorKind, Read}, -}; +use std::{borrow::Borrow, collections::HashMap, io::Read}; use uuid::Uuid; #[inline]