You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by mg...@apache.org on 2022/12/18 19:58:22 UTC

[avro] branch branch-1.11 updated: AVRO-3692: [rust] Make serde deserializer support serde flatten (#2024)

This is an automated email from the ASF dual-hosted git repository.

mgrigorov pushed a commit to branch branch-1.11
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/branch-1.11 by this push:
     new f4bcb7200 AVRO-3692: [rust] Make serde deserializer support serde flatten (#2024)
f4bcb7200 is described below

commit f4bcb7200f74a055d2daaee399f802e52d1b87b4
Author: Ten0 <90...@users.noreply.github.com>
AuthorDate: Sun Dec 18 20:57:28 2022 +0100

    AVRO-3692: [rust] Make serde deserializer support serde flatten (#2024)
    
    * Make serde deserializer support serde flatten
    
    * Update test name to include avro ticket id
    
    Co-authored-by: Martin Grigorov <ma...@users.noreply.github.com>
    
    * give more details in not-record-nor-map error
    
    Co-authored-by: Martin Grigorov <ma...@users.noreply.github.com>
    (cherry picked from commit a02e974181724a8abb9120424e9d8590b0d852a4)
---
 lang/rust/avro/src/de.rs | 53 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/lang/rust/avro/src/de.rs b/lang/rust/avro/src/de.rs
index 1d3b50360..9204ed146 100644
--- a/lang/rust/avro/src/de.rs
+++ b/lang/rust/avro/src/de.rs
@@ -42,7 +42,7 @@ struct MapDeserializer<'de> {
     input_values: Values<'de, String, Value>,
 }
 
-struct StructDeserializer<'de> {
+struct RecordDeserializer<'de> {
     input: Iter<'de, (String, Value)>,
     value: Option<&'de Value>,
 }
@@ -72,17 +72,15 @@ impl<'de> SeqDeserializer<'de> {
 impl<'de> MapDeserializer<'de> {
     pub fn new(input: &'de HashMap<String, Value>) -> Self {
         MapDeserializer {
-            input_keys: input.keys(), // input.keys().map(|k| Value::String(k.clone())).collect::<Vec<_>>().iter(),
+            input_keys: input.keys(),
             input_values: input.values(),
-            // keys: input.keys().map(|s| Value::String(s.to_owned())).collect::<Vec<Value>>(),
-            // values: input.values().map(|s| s.to_owned()).collect::<Vec<Value>>(),
         }
     }
 }
 
-impl<'de> StructDeserializer<'de> {
+impl<'de> RecordDeserializer<'de> {
     pub fn new(input: &'de [(String, Value)]) -> Self {
-        StructDeserializer {
+        RecordDeserializer {
             input: input.iter(),
             value: None,
         }
@@ -260,7 +258,7 @@ impl<'a, 'de> de::Deserializer<'de> for &'a Deserializer<'de> {
                 | Value::TimestampMicros(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(StructDeserializer::new(fields)),
+                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::Map(ref items) => visitor.visit_map(MapDeserializer::new(items)),
@@ -269,7 +267,7 @@ impl<'a, 'de> de::Deserializer<'de> for &'a Deserializer<'de> {
                     self.input
                 ))),
             },
-            Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
+            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::Map(ref items) => visitor.visit_map(MapDeserializer::new(items)),
@@ -435,7 +433,11 @@ impl<'a, 'de> de::Deserializer<'de> for &'a Deserializer<'de> {
     {
         match *self.input {
             Value::Map(ref items) => visitor.visit_map(MapDeserializer::new(items)),
-            _ => Err(de::Error::custom("not a map")),
+            Value::Record(ref fields) => visitor.visit_map(RecordDeserializer::new(fields)),
+            _ => Err(de::Error::custom(format_args!(
+                "Expected a record or a map. Got: {:?}",
+                &self.input
+            ))),
         }
     }
 
@@ -449,9 +451,9 @@ impl<'a, 'de> de::Deserializer<'de> for &'a Deserializer<'de> {
         V: Visitor<'de>,
     {
         match *self.input {
-            Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
+            Value::Record(ref fields) => visitor.visit_map(RecordDeserializer::new(fields)),
             Value::Union(_i, ref inner) => match **inner {
-                Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
+                Value::Record(ref fields) => visitor.visit_map(RecordDeserializer::new(fields)),
                 _ => Err(de::Error::custom("not a record")),
             },
             _ => Err(de::Error::custom("not a record")),
@@ -533,7 +535,7 @@ impl<'de> de::MapAccess<'de> for MapDeserializer<'de> {
     }
 }
 
-impl<'de> de::MapAccess<'de> for StructDeserializer<'de> {
+impl<'de> de::MapAccess<'de> for RecordDeserializer<'de> {
     type Error = Error;
 
     fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
@@ -857,6 +859,33 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_avro_3692_from_value_struct_flatten() {
+        #[derive(Deserialize, PartialEq, Debug)]
+        struct S1 {
+            f1: String,
+            #[serde(flatten)]
+            inner: S2,
+        }
+        #[derive(Deserialize, PartialEq, Debug)]
+        struct S2 {
+            f2: String,
+        }
+        let expected = S1 {
+            f1: "Hello".to_owned(),
+            inner: S2 {
+                f2: "World".to_owned(),
+            },
+        };
+
+        let test = Value::Record(vec![
+            ("f1".to_owned(), "Hello".into()),
+            ("f2".to_owned(), "World".into()),
+        ]);
+        let final_value: S1 = from_value(&test).unwrap();
+        assert_eq!(final_value, expected);
+    }
+
     #[test]
     fn test_from_value_tuple_enum() {
         let expected = TestTupleExternalEnum {