This is an automated email from the ASF dual-hosted git repository.
kriskras99 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/avro-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 9b15ed4 fix: Simplify deserializer (#416)
9b15ed4 is described below
commit 9b15ed49f4b17487a6e1b73277faaef32837b279
Author: Kriskras99 <[email protected]>
AuthorDate: Tue Jan 20 09:45:22 2026 +0100
fix: Simplify deserializer (#416)
Removed an unnecessary indirection through a reference.
Also replaced `Union` matches with a recursive call.
---
avro/src/serde/de.rs | 271 +++++++++++++++++++++------------------------------
1 file changed, 111 insertions(+), 160 deletions(-)
diff --git a/avro/src/serde/de.rs b/avro/src/serde/de.rs
index 257dd6a..6779502 100644
--- a/avro/src/serde/de.rs
+++ b/avro/src/serde/de.rs
@@ -216,7 +216,7 @@ impl<'de> de::VariantAccess<'de> for EnumDeserializer<'de> {
Err(de::Error::custom(
"Expected a newtype variant, got nothing instead.",
)),
- |item| seed.deserialize(&Deserializer::new(&item.1)),
+ |item| seed.deserialize(Deserializer::new(&item.1)),
)
}
@@ -228,7 +228,7 @@ impl<'de> de::VariantAccess<'de> for EnumDeserializer<'de> {
Err(de::Error::custom(
"Expected a tuple variant, got nothing instead.",
)),
- |item|
de::Deserializer::deserialize_seq(&Deserializer::new(&item.1), visitor),
+ |item|
de::Deserializer::deserialize_seq(Deserializer::new(&item.1), visitor),
)
}
@@ -244,7 +244,7 @@ impl<'de> de::VariantAccess<'de> for EnumDeserializer<'de> {
Err(de::Error::custom("Expected a struct variant, got nothing")),
|item| {
de::Deserializer::deserialize_struct(
- &Deserializer::new(&item.1),
+ Deserializer::new(&item.1),
"",
fields,
visitor,
@@ -286,7 +286,7 @@ impl<'de> de::VariantAccess<'de> for UnionDeserializer<'de>
{
where
T: DeserializeSeed<'de>,
{
- seed.deserialize(&Deserializer::new(self.value))
+ seed.deserialize(Deserializer::new(self.value))
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value,
Self::Error>
@@ -309,7 +309,7 @@ impl<'de> de::VariantAccess<'de> for UnionDeserializer<'de>
{
}
}
-impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
+impl<'de> de::Deserializer<'de> for Deserializer<'de> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@@ -330,40 +330,19 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
| Value::LocalTimestampNanos(i) => visitor.visit_i64(*i),
&Value::Float(f) => visitor.visit_f32(f),
&Value::Double(d) => visitor.visit_f64(d),
- Value::Union(_i, u) => match **u {
- Value::Null => visitor.visit_unit(),
- Value::Boolean(b) => visitor.visit_bool(b),
- Value::Int(i) | Value::Date(i) | Value::TimeMillis(i) =>
visitor.visit_i32(i),
- Value::Long(i)
- | Value::TimeMicros(i)
- | Value::TimestampMillis(i)
- | Value::TimestampMicros(i)
- | Value::TimestampNanos(i)
- | Value::LocalTimestampMillis(i)
- | Value::LocalTimestampMicros(i)
- | Value::LocalTimestampNanos(i) => visitor.visit_i64(i),
- Value::Float(f) => visitor.visit_f32(f),
- Value::Double(d) => visitor.visit_f64(d),
- Value::Record(ref fields) =>
visitor.visit_map(RecordDeserializer::new(fields)),
- Value::Array(ref fields) =>
visitor.visit_seq(SeqDeserializer::new(fields)),
- Value::String(ref s) => visitor.visit_borrowed_str(s),
- Value::Uuid(uuid) => visitor.visit_str(&uuid.to_string()),
- Value::Map(ref items) =>
visitor.visit_map(MapDeserializer::new(items)),
- Value::Bytes(ref bytes) | Value::Fixed(_, ref bytes) =>
visitor.visit_bytes(bytes),
- Value::Decimal(ref d) => visitor.visit_bytes(&d.to_vec()?),
- Value::Enum(_, ref s) => visitor.visit_borrowed_str(s),
- Value::BigDecimal(ref big_decimal) => {
- visitor.visit_str(big_decimal.to_plain_string().as_str())
- }
- Value::Duration(ref duration) => {
- let duration_bytes: [u8; 12] = duration.into();
- visitor.visit_bytes(&duration_bytes[..])
+ Value::Union(i, x) => {
+ if matches!(x.deref(), Value::Union(_, _)) {
+ Err(de::Error::custom(format!(
+ "Directly nested union types are not supported. Got
Value::Union({i}, {x:?})"
+ )))
+ } else {
+ Self::new(x.deref()).deserialize_any(visitor).map_err(|e| {
+ de::Error::custom(format!(
+ "Attempted to deserialize Value::Union({i}, {x:?})
as any: {e:?}"
+ ))
+ })
}
- Value::Union(_, _) => Err(de::Error::custom(format!(
- "Directly nested union types are not supported. Got {:?}",
- &**u
- ))),
- },
+ }
Value::Record(fields) =>
visitor.visit_map(RecordDeserializer::new(fields)),
Value::Array(fields) =>
visitor.visit_seq(SeqDeserializer::new(fields)),
Value::String(s) => visitor.visit_borrowed_str(s),
@@ -410,31 +389,19 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
let n =
u64::from_le_bytes(bytes.as_slice().try_into().expect("Size is 8"));
visitor.visit_u64(n)
}
- Value::Union(_i, x) => match x.deref() {
- Value::Int(i) | Value::Date(i) | Value::TimeMillis(i) => {
- let n = u64::try_from(*i).map_err(|e|
Details::ConvertI32ToU64(e, *i))?;
- visitor.visit_u64(n)
- }
- Value::Long(i)
- | Value::TimeMicros(i)
- | Value::TimestampMillis(i)
- | Value::TimestampMicros(i)
- | Value::TimestampNanos(i)
- | Value::LocalTimestampMillis(i)
- | Value::LocalTimestampMicros(i)
- | Value::LocalTimestampNanos(i) => {
- let n = u64::try_from(*i).map_err(|e|
Details::ConvertI64ToU64(e, *i))?;
- visitor.visit_u64(n)
- }
- Value::Fixed(8, bytes) => {
- let n =
u64::from_le_bytes(bytes.as_slice().try_into().expect("Size is 8"));
- visitor.visit_u64(n)
+ Value::Union(i, x) => {
+ if matches!(x.deref(), Value::Union(_, _)) {
+ Err(de::Error::custom(format!(
+ "Directly nested union types are not supported. Got
Value::Union({i}, {x:?})"
+ )))
+ } else {
+ Self::new(x.deref()).deserialize_u64(visitor).map_err(|e| {
+ de::Error::custom(format!(
+ "Attempted to deserialize Value::Union({i}, {x:?})
as u64: {e:?}"
+ ))
+ })
}
- _ => Err(de::Error::custom(format!(
- "Expected a Int|Long|Fixed(8), but got {:?}",
- self.input
- ))),
- },
+ }
_ => Err(de::Error::custom(format!(
"Expected a Int|Long|Fixed(8), but got {:?}",
self.input
@@ -466,31 +433,19 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
let n =
u128::from_le_bytes(bytes.as_slice().try_into().expect("Size is 16"));
visitor.visit_u128(n)
}
- Value::Union(_i, x) => match x.deref() {
- Value::Int(i) | Value::Date(i) | Value::TimeMillis(i) => {
- let n = u128::try_from(*i).map_err(|e|
Details::ConvertI32ToU128(e, *i))?;
- visitor.visit_u128(n)
- }
- Value::Long(i)
- | Value::TimeMicros(i)
- | Value::TimestampMillis(i)
- | Value::TimestampMicros(i)
- | Value::TimestampNanos(i)
- | Value::LocalTimestampMillis(i)
- | Value::LocalTimestampMicros(i)
- | Value::LocalTimestampNanos(i) => {
- let n = u128::try_from(*i).map_err(|e|
Details::ConvertI64ToU128(e, *i))?;
- visitor.visit_u128(n)
- }
- Value::Fixed(16, bytes) => {
- let n =
u128::from_le_bytes(bytes.as_slice().try_into().expect("Size is 16"));
- visitor.visit_u128(n)
+ Value::Union(i, x) => {
+ if matches!(x.deref(), Value::Union(_, _)) {
+ Err(de::Error::custom(format!(
+ "Directly nested union types are not supported. Got
Value::Union({i}, {x:?})"
+ )))
+ } else {
+ Self::new(x.deref()).deserialize_u128(visitor).map_err(|e|
{
+ de::Error::custom(format!(
+ "Attempted to deserialize Value::Union({i}, {x:?})
as u128: {e:?}"
+ ))
+ })
}
- _ => Err(de::Error::custom(format!(
- "Expected a Int|Long|Fixed(16), but got {:?}",
- self.input
- ))),
- },
+ }
_ => Err(de::Error::custom(format!(
"Expected a Int|Long|Fixed(16), but got {:?}",
self.input
@@ -518,27 +473,19 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
let n =
i128::from_le_bytes(bytes.as_slice().try_into().expect("Size is 16"));
visitor.visit_i128(n)
}
- Value::Union(_i, x) => match x.deref() {
- Value::Int(i) | Value::Date(i) | Value::TimeMillis(i) => {
- visitor.visit_i128(i128::from(*i))
- }
- Value::Long(i)
- | Value::TimeMicros(i)
- | Value::TimestampMillis(i)
- | Value::TimestampMicros(i)
- | Value::TimestampNanos(i)
- | Value::LocalTimestampMillis(i)
- | Value::LocalTimestampMicros(i)
- | Value::LocalTimestampNanos(i) =>
visitor.visit_i128(i128::from(*i)),
- Value::Fixed(16, bytes) => {
- let n =
i128::from_le_bytes(bytes.as_slice().try_into().expect("Size is 16"));
- visitor.visit_i128(n)
+ Value::Union(i, x) => {
+ if matches!(x.deref(), Value::Union(_, _)) {
+ Err(de::Error::custom(format!(
+ "Directly nested union types are not supported. Got
Value::Union({i}, {x:?})"
+ )))
+ } else {
+ Self::new(x.deref()).deserialize_i128(visitor).map_err(|e|
{
+ de::Error::custom(format!(
+ "Attempted to deserialize Value::Union({i}, {x:?})
as i128: {e:?}"
+ ))
+ })
}
- _ => Err(de::Error::custom(format!(
- "Expected a Int|Long|Fixed(16), but got {:?}",
- self.input
- ))),
- },
+ }
_ => Err(de::Error::custom(format!(
"Expected a Int|Long|Fixed(16), but got {:?}",
self.input
@@ -571,28 +518,18 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
Value::Fixed(4, bytes) => {
visitor.visit_char(char::from_u32(u32::from_le_bytes(bytes.as_slice().try_into().expect("Size
is 4"))).ok_or_else(|| <Self::Error as de::Error>::custom("Tried to
deserialize char from fixed, but was invalid value"))?)
}
- Value::Union(_i, x) => match x.deref() {
- Value::String(s) => {
- if s.chars().count() == 1 {
- visitor.visit_char(s.chars().next().expect("There is
exactly one char"))
- } else {
- Err(de::Error::custom(format!("Tried to deserialize
char from string, but the string was longer than one char: {s}")))
- }
- }
- Value::Bytes(bytes) => std::str::from_utf8(bytes)
- .map_err(|e| de::Error::custom(e.to_string()))
- .and_then(|s| {
- if s.chars().count() == 1 {
- visitor.visit_char(s.chars().next().expect("There
is exactly one char"))
- } else {
- Err(de::Error::custom(format!("Tried to
deserialize char from a byte array, but the byte array was longer than one
char: {}", s.len())))
- }
- }
- ),
- Value::Fixed(4, bytes) => {
-
visitor.visit_char(char::from_u32(u32::from_le_bytes(bytes.as_slice().try_into().expect("Size
is 4"))).ok_or_else(|| <Self::Error as de::Error>::custom("Tried to
deserialize char from fixed, but was invalid value"))?)
+ Value::Union(i, x) => {
+ if matches!(x.deref(), Value::Union(_, _)) {
+ Err(de::Error::custom(format!(
+ "Directly nested union types are not supported. Got
Value::Union({i}, {x:?})"
+ )))
+ } else {
+ Self::new(x.deref()).deserialize_char(visitor).map_err(|e|
{
+ de::Error::custom(format!(
+ "Attempted to deserialize Value::Union({i}, {x:?})
as char: {e:?}"
+ ))
+ })
}
- _ => Err(de::Error::custom(format!("Expected a
String|Bytes|Fixed(4) for char, but got {:?}", self.input)))
},
_ => Err(de::Error::custom(format!("Expected a
String|Bytes|Fixed(4) for char, but got {:?}", self.input)))
}
@@ -608,16 +545,19 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
.map_err(|e| de::Error::custom(e.to_string()))
.and_then(|s| visitor.visit_borrowed_str(s)),
Value::Uuid(u) => visitor.visit_str(&u.to_string()),
- Value::Union(_i, x) => match x.deref() {
- Value::String(s) => visitor.visit_borrowed_str(s),
- Value::Bytes(bytes) | Value::Fixed(_, bytes) =>
std::str::from_utf8(bytes)
- .map_err(|e| de::Error::custom(e.to_string()))
- .and_then(|s| visitor.visit_borrowed_str(s)),
- Value::Uuid(u) => visitor.visit_str(&u.to_string()),
- _ => Err(de::Error::custom(format!(
- "Expected a String|Bytes|Fixed|Uuid, but got {x:?}"
- ))),
- },
+ Value::Union(i, x) => {
+ if matches!(x.deref(), Value::Union(_, _)) {
+ Err(de::Error::custom(format!(
+ "Directly nested union types are not supported. Got
Value::Union({i}, {x:?})"
+ )))
+ } else {
+ Self::new(x.deref()).deserialize_str(visitor).map_err(|e| {
+ de::Error::custom(format!(
+ "Attempted to deserialize Value::Union({i}, {x:?})
as str: {e:?}"
+ ))
+ })
+ }
+ }
_ => Err(de::Error::custom(format!(
"Expected a String|Bytes|Fixed|Uuid, but got {:?}",
self.input
@@ -635,16 +575,21 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
.map_err(|e| de::Error::custom(e.to_string()))
.and_then(|s| visitor.visit_string(s)),
Value::Uuid(u) => visitor.visit_str(&u.to_string()),
- Value::Union(_i, x) => match x.deref() {
- Value::String(s) => visitor.visit_borrowed_str(s),
- Value::Bytes(bytes) | Value::Fixed(_, bytes) =>
String::from_utf8(bytes.to_owned())
- .map_err(|e| de::Error::custom(e.to_string()))
- .and_then(|s| visitor.visit_string(s)),
- Value::Uuid(u) => visitor.visit_str(&u.to_string()),
- _ => Err(de::Error::custom(format!(
- "Expected a String|Bytes|Fixed|Uuid, but got {x:?}"
- ))),
- },
+ Value::Union(i, x) => {
+ if matches!(x.deref(), Value::Union(_, _)) {
+ Err(de::Error::custom(format!(
+ "Directly nested union types are not supported. Got
Value::Union({i}, {x:?})"
+ )))
+ } else {
+ Self::new(x.deref())
+ .deserialize_string(visitor)
+ .map_err(|e| {
+ de::Error::custom(format!(
+ "Attempted to deserialize Value::Union({i},
{x:?}) as string: {e:?}"
+ ))
+ })
+ }
+ }
_ => Err(de::Error::custom(format!(
"Expected a String|Bytes|Fixed|Uuid|Union|Enum, but got {:?}",
self.input
@@ -706,7 +651,7 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
{
match self.input {
Value::Union(_i, inner) if inner.as_ref() == &Value::Null =>
visitor.visit_none(),
- Value::Union(_i, inner) =>
visitor.visit_some(&Deserializer::new(inner)),
+ Value::Union(_i, inner) =>
visitor.visit_some(Deserializer::new(inner)),
_ => Err(de::Error::custom(format!(
"Expected a Union, but got {:?}",
self.input
@@ -720,13 +665,19 @@ impl<'de> de::Deserializer<'de> for &Deserializer<'de> {
{
match self.input {
Value::Null => visitor.visit_unit(),
- Value::Union(_i, x) => match **x {
- Value::Null => visitor.visit_unit(),
- _ => Err(de::Error::custom(format!(
- "Expected a Null, but got {:?}",
- self.input
- ))),
- },
+ Value::Union(i, x) => {
+ if matches!(x.deref(), Value::Union(_, _)) {
+ Err(de::Error::custom(format!(
+ "Directly nested union types are not supported. Got
Value::Union({i}, {x:?})"
+ )))
+ } else {
+ Self::new(x.deref()).deserialize_unit(visitor).map_err(|e|
{
+ de::Error::custom(format!(
+ "Attempted to deserialize Value::Union({i}, {x:?})
as unit: {e:?}"
+ ))
+ })
+ }
+ }
_ => Err(de::Error::custom(format!(
"Expected a Null|Union, but got {:?}",
self.input
@@ -897,7 +848,7 @@ impl<'de> de::SeqAccess<'de> for SeqDeserializer<'de> {
T: DeserializeSeed<'de>,
{
match self.input.next() {
- Some(item) => seed.deserialize(&Deserializer::new(item)).map(Some),
+ Some(item) => seed.deserialize(Deserializer::new(item)).map(Some),
None => Ok(None),
}
}
@@ -925,7 +876,7 @@ impl<'de> de::MapAccess<'de> for MapDeserializer<'de> {
V: DeserializeSeed<'de>,
{
match self.input_values.next() {
- Some(value) => seed.deserialize(&Deserializer::new(value)),
+ Some(value) => seed.deserialize(Deserializer::new(value)),
None => Err(de::Error::custom("should not happen - too many
values")),
}
}
@@ -955,7 +906,7 @@ impl<'de> de::MapAccess<'de> for RecordDeserializer<'de> {
V: DeserializeSeed<'de>,
{
match self.value.take() {
- Some(value) => seed.deserialize(&Deserializer::new(value)),
+ Some(value) => seed.deserialize(Deserializer::new(value)),
None => Err(de::Error::custom("should not happen - too many
values")),
}
}
@@ -989,7 +940,7 @@ impl<'de> de::Deserializer<'de> for StringDeserializer {
/// structure expected by `D`.
pub fn from_value<'de, D: Deserialize<'de>>(value: &'de Value) -> Result<D,
Error> {
let de = Deserializer::new(value);
- D::deserialize(&de)
+ D::deserialize(de)
}
#[cfg(test)]
@@ -1774,7 +1725,7 @@ mod tests {
assert!(!crate::util::is_human_readable());
- let deser = &Deserializer::new(&Value::Null);
+ let deser = Deserializer::new(&Value::Null);
assert!(!deser.is_human_readable());