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
The following commit(s) were added to refs/heads/main by this push:
new d6eb573 Use custom serde serialization and deserialization for avro
decimal (#48)
d6eb573 is described below
commit d6eb573e6443ca545c45bcd47f60a9acea61db1e
Author: Ole Hjalmar Herje <[email protected]>
AuthorDate: Fri Nov 8 13:14:27 2024 +0100
Use custom serde serialization and deserialization for avro decimal (#48)
* Use custom serde serialization and deserialization for avro decimal
* Issue #48 - Fix the formatting
Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
* Issue #40 - Minor cleanup
Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
---------
Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
Co-authored-by: k01157 <[email protected]>
Co-authored-by: Martin Tzvetanov Grigorov <[email protected]>
---
avro/src/de.rs | 4 ++++
avro/src/decimal.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
avro/src/ser.rs | 5 +++++
3 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/avro/src/de.rs b/avro/src/de.rs
index 6745152..a932075 100644
--- a/avro/src/de.rs
+++ b/avro/src/de.rs
@@ -771,6 +771,7 @@ mod tests {
struct Test {
a: i64,
b: String,
+ c: Decimal,
}
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
@@ -864,10 +865,12 @@ mod tests {
let test = Value::Record(vec![
("a".to_owned(), Value::Long(27)),
("b".to_owned(), Value::String("foo".to_owned())),
+ ("c".to_owned(), Value::Decimal(Decimal::from(vec![1, 24]))),
]);
let expected = Test {
a: 27,
b: "foo".to_owned(),
+ c: Decimal::from(vec![1, 24]),
};
let final_value: Test = from_value(&test)?;
assert_eq!(final_value, expected);
@@ -878,6 +881,7 @@ mod tests {
Value::Record(vec![
("a".to_owned(), Value::Long(27)),
("b".to_owned(), Value::String("foo".to_owned())),
+ ("c".to_owned(), Value::Decimal(Decimal::from(vec![1,
24]))),
]),
),
("b".to_owned(), Value::Int(35)),
diff --git a/avro/src/decimal.rs b/avro/src/decimal.rs
index 6854f34..e871e58 100644
--- a/avro/src/decimal.rs
+++ b/avro/src/decimal.rs
@@ -17,13 +17,60 @@
use crate::{AvroResult, Error};
use num_bigint::{BigInt, Sign};
+use serde::{de::SeqAccess, Deserialize, Serialize, Serializer};
-#[derive(Debug, Clone, Eq, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, Clone, Eq)]
pub struct Decimal {
value: BigInt,
len: usize,
}
+impl Serialize for Decimal {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match self.to_vec() {
+ Ok(ref bytes) => serializer.serialize_bytes(bytes),
+ Err(e) => Err(serde::ser::Error::custom(e)),
+ }
+ }
+}
+impl<'de> Deserialize<'de> for Decimal {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ struct DecimalVisitor;
+ impl<'de> serde::de::Visitor<'de> for DecimalVisitor {
+ type Value = Decimal;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) ->
std::fmt::Result {
+ formatter.write_str("a byte slice or seq of bytes")
+ }
+
+ fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ Ok(Decimal::from(v))
+ }
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut bytes = Vec::new();
+ while let Some(value) = seq.next_element::<u8>()? {
+ bytes.push(value);
+ }
+
+ Ok(Decimal::from(bytes))
+ }
+ }
+ deserializer.deserialize_bytes(DecimalVisitor)
+ }
+}
+
// We only care about value equality, not byte length. Can two equal `BigInt`s
have two different
// byte lengths?
impl PartialEq for Decimal {
diff --git a/avro/src/ser.rs b/avro/src/ser.rs
index 519306a..32d496b 100644
--- a/avro/src/ser.rs
+++ b/avro/src/ser.rs
@@ -488,6 +488,7 @@ pub fn to_value<S: Serialize>(value: S) -> Result<Value,
Error> {
#[cfg(test)]
mod tests {
use super::*;
+ use crate::Decimal;
use apache_avro_test_helper::TestResult;
use pretty_assertions::assert_eq;
use serde::{Deserialize, Serialize};
@@ -498,6 +499,7 @@ mod tests {
struct Test {
a: i64,
b: String,
+ decimal: Decimal,
}
#[derive(Debug, Deserialize, Serialize)]
@@ -688,10 +690,12 @@ mod tests {
let test = Test {
a: 27,
b: "foo".to_owned(),
+ decimal: Decimal::from(vec![1, 24]),
};
let expected = Value::Record(vec![
("a".to_owned(), Value::Long(27)),
("b".to_owned(), Value::String("foo".to_owned())),
+ ("decimal".to_owned(), Value::Bytes(vec![1, 24])),
]);
assert_eq!(to_value(test.clone())?, expected);
@@ -704,6 +708,7 @@ mod tests {
Value::Record(vec![
("a".to_owned(), Value::Long(27)),
("b".to_owned(), Value::String("foo".to_owned())),
+ ("decimal".to_owned(), Value::Bytes(vec![1, 24])),
]),
),
("b".to_owned(), Value::Int(35)),