You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by kr...@apache.org on 2026/09/06 13:23:27 UTC
(avro-rs) 01/01: feat: Optimize UUID decoding in `decode.rs`
This is an automated email from the ASF dual-hosted git repository.
Kriskras99 pushed a commit to branch opt/decode_uuid
in repository https://gitbox.apache.org/repos/asf/avro-rs.git
commit 10a4b3402f7f0b5457bddd37909d801197fe4421
Author: Kriskras99 <gi...@kriskras99.nl>
AuthorDate: Sun Sep 6 15:22:34 2026 +0200
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 e29daa7..941dc10 100644
--- a/avro/src/decode.rs
+++ b/avro/src/decode.rs
@@ -222,46 +222,42 @@ fn decode_internal_body<R: Read, S: Borrow<Schema>>(
}
}
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 6723340..74ea9d4 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),