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)),

Reply via email to