martin-g commented on code in PR #359:
URL: https://github.com/apache/avro-rs/pull/359#discussion_r2599955229


##########
avro/src/serde/ser_schema.rs:
##########
@@ -420,6 +425,50 @@ impl<W: Write> ser::SerializeStruct for 
SchemaAwareWriteSerializeStruct<'_, '_,
     }
 }
 
+impl<W: Write> ser::SerializeMap for SchemaAwareWriteSerializeStruct<'_, '_, 
W> {
+    type Ok = usize;
+    type Error = Error;
+
+    fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        let name = key.serialize(StringSerializer)?;
+        assert!(

Review Comment:
   ```suggestion
           debug_assert!(
   ```



##########
avro/src/serde/ser_schema.rs:
##########
@@ -352,6 +356,10 @@ impl<'a, 's, W: Write> SchemaAwareWriteSerializeStruct<'a, 
's, W> {
             "There should be no more unwritten fields at this point: {:?}",
             self.field_cache
         );
+        assert!(
+            self.map_field_name.is_none(),
+            "There should be no field name at this point"

Review Comment:
   ```suggestion
               "There should be no field name at this point: {}", 
self.map_field_name
   ```



##########
avro/src/serde/ser_schema.rs:
##########
@@ -420,6 +425,50 @@ impl<W: Write> ser::SerializeStruct for 
SchemaAwareWriteSerializeStruct<'_, '_,
     }
 }
 
+impl<W: Write> ser::SerializeMap for SchemaAwareWriteSerializeStruct<'_, '_, 
W> {
+    type Ok = usize;
+    type Error = Error;
+
+    fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        let name = key.serialize(StringSerializer)?;
+        assert!(
+            self.map_field_name.replace(name).is_none(),
+            "Got two keys in a row"
+        );
+        Ok(())
+    }
+
+    fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        let key = self.map_field_name.take().expect("Got value without key");

Review Comment:
   Let's return an Avro error instead of crashing.



##########
avro_derive/tests/derive.rs:
##########
@@ -1686,4 +1686,103 @@ mod test_derive {
             panic!("Unexpected schema type for Foo")
         }
     }
+
+    #[test]
+    fn avro_247_serde_flatten_support() {

Review Comment:
   ```suggestion
       fn avro_rs_247_serde_flatten_support() {
   ```
   The tests without `_rs` are pointing to the old JIRA tickets. 



##########
avro_derive/src/lib.rs:
##########
@@ -142,26 +144,46 @@ fn get_data_struct_schema_def(
     let mut record_field_exprs = vec![];
     match s.fields {
         syn::Fields::Named(ref a) => {
-            let mut index: usize = 0;
             for field in a.named.iter() {
-                let mut name = field.ident.as_ref().unwrap().to_string(); // 
we know everything has a name
+                let mut name = field
+                    .ident
+                    .as_ref()
+                    .expect("Field must have a name")
+                    .to_string();
                 if let Some(raw_name) = name.strip_prefix("r#") {
                     name = raw_name.to_string();
                 }
                 let field_attrs =
-                    
FieldOptions::from_attributes(&field.attrs[..]).map_err(darling_to_syn)?;
+                    
FieldOptions::from_attributes(&field.attrs).map_err(darling_to_syn)?;
                 let doc =
                     preserve_optional(field_attrs.doc.or_else(|| 
extract_outer_doc(&field.attrs)));
                 match (field_attrs.rename, rename_all) {
                     (Some(rename), _) => {
                         name = rename;
                     }
-                    (None, rename_all) if !matches!(rename_all, 
RenameRule::None) => {
+                    (None, rename_all) if rename_all != RenameRule::None => {
                         name = rename_all.apply_to_field(&name);
                     }
                     _ => {}
                 }
-                if let Some(true) = field_attrs.skip {
+                if Some(true) == field_attrs.skip {
+                    continue;
+                } else if Some(true) == field_attrs.flatten {
+                    // Inline the fields of the child record at runtime, as we 
don't have access to
+                    // the schema here.
+                    let flatten_ty = &field.ty;
+                    record_field_exprs.push(quote! {
+                        if let 
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema { 
fields, .. }) = #flatten_ty::get_schema() {
+                            for mut field in fields {
+                                field.position = schema_fields.len();
+                                schema_fields.push(field)
+                            }
+                        } else {
+                            panic!("Can only flatten RecordSchema")

Review Comment:
   Return a syn::Error instead of panicking ?!



##########
avro/src/serde/ser_schema.rs:
##########


Review Comment:
   Add support for Schema::Record and maybe for Schema::Ref too



##########
avro_derive/tests/derive.rs:
##########
@@ -1686,4 +1686,103 @@ mod test_derive {
             panic!("Unexpected schema type for Foo")
         }
     }
+
+    #[test]
+    fn avro_247_serde_flatten_support() {
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Nested {
+            a: bool,
+        }
+
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Foo {
+            #[serde(flatten)]
+            #[avro(flatten)]
+            nested: Nested,
+            b: i32,
+        }
+
+        let schema = r#"
+        {
+            "type":"record",
+            "name":"Foo",
+            "fields": [
+                {
+                    "name":"a",
+                    "type":"boolean"
+                },
+                {
+                    "name":"b",
+                    "type":"int"
+                }
+            ]
+        }
+        "#;
+
+        let schema = Schema::parse_str(schema).unwrap();
+        let derived_schema = Foo::get_schema();
+        if let Schema::Record(RecordSchema { name, fields, .. }) = 
&derived_schema {
+            assert_eq!("Foo", name.fullname(None));
+            for field in fields {
+                match field.name.as_str() {
+                    "a" | "b" => (), // expected
+                    name => panic!("Unexpected field name '{name}'"),
+                }
+            }
+        } else {
+            panic!("Foo schema must be a record schema: {derived_schema:?}")
+        }
+        assert_eq!(schema, derived_schema);
+
+        serde_assert(Foo {
+            nested: Nested { a: true },
+            b: 321,
+        });
+    }
+
+    #[test]
+    fn avro_247_serde_nested_flatten_support() {

Review Comment:
   ```suggestion
       fn avro_rs_247_serde_nested_flatten_support() {
   ```



##########
avro_derive/tests/derive.rs:
##########
@@ -1686,4 +1686,103 @@ mod test_derive {
             panic!("Unexpected schema type for Foo")
         }
     }
+
+    #[test]
+    fn avro_247_serde_flatten_support() {

Review Comment:
   Any reason against returning `TestResult` and get rid of the `.unwrap()`s 
below ?



##########
avro/src/serde/ser_schema.rs:
##########
@@ -352,6 +356,10 @@ impl<'a, 's, W: Write> SchemaAwareWriteSerializeStruct<'a, 
's, W> {
             "There should be no more unwritten fields at this point: {:?}",
             self.field_cache
         );
+        assert!(

Review Comment:
   ```suggestion
           debug_assert!(
   ```



##########
avro_derive/tests/derive.rs:
##########
@@ -1686,4 +1686,103 @@ mod test_derive {
             panic!("Unexpected schema type for Foo")
         }
     }
+
+    #[test]
+    fn avro_247_serde_flatten_support() {
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Nested {
+            a: bool,
+        }
+
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Foo {
+            #[serde(flatten)]
+            #[avro(flatten)]
+            nested: Nested,
+            b: i32,
+        }
+
+        let schema = r#"
+        {
+            "type":"record",
+            "name":"Foo",
+            "fields": [
+                {
+                    "name":"a",
+                    "type":"boolean"
+                },
+                {
+                    "name":"b",
+                    "type":"int"
+                }
+            ]
+        }
+        "#;
+
+        let schema = Schema::parse_str(schema).unwrap();
+        let derived_schema = Foo::get_schema();
+        if let Schema::Record(RecordSchema { name, fields, .. }) = 
&derived_schema {
+            assert_eq!("Foo", name.fullname(None));
+            for field in fields {
+                match field.name.as_str() {
+                    "a" | "b" => (), // expected
+                    name => panic!("Unexpected field name '{name}'"),
+                }
+            }
+        } else {
+            panic!("Foo schema must be a record schema: {derived_schema:?}")
+        }
+        assert_eq!(schema, derived_schema);
+
+        serde_assert(Foo {
+            nested: Nested { a: true },
+            b: 321,
+        });
+    }
+
+    #[test]
+    fn avro_247_serde_nested_flatten_support() {

Review Comment:
   Any reason against returning `TestResult` and get rid of the `.unwrap()`s 
below ?



##########
avro/src/serde/ser_schema.rs:
##########
@@ -420,6 +425,50 @@ impl<W: Write> ser::SerializeStruct for 
SchemaAwareWriteSerializeStruct<'_, '_,
     }
 }
 
+impl<W: Write> ser::SerializeMap for SchemaAwareWriteSerializeStruct<'_, '_, 
W> {
+    type Ok = usize;
+    type Error = Error;
+
+    fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        let name = key.serialize(StringSerializer)?;
+        assert!(
+            self.map_field_name.replace(name).is_none(),
+            "Got two keys in a row"

Review Comment:
   The error message is not very clear to me.
   Let's extract the result of `Option::replace()` to a local variable and 
print it in case of an error.



##########
avro_derive/src/lib.rs:
##########
@@ -39,6 +39,8 @@ struct FieldOptions {
     rename: Option<String>,
     #[darling(default)]
     skip: Option<bool>,
+    #[darling(default)]
+    flatten: Option<bool>,

Review Comment:
   IMO we could define a 
   ```rust
   #[derive(darling::FromAttributes)]
   #[darling(attributes(serde))]
   struct SerdeOptions {
   ...
   }
   ```
   and move all serde-related options here.
   This way there won't be a need the user application to duplicate all of them 
in the `avro(...)` namespace.
   This will be a breaking change but I think the users will appreciate it in 
the long term. At the moment it is possible to have a field with only serde's 
or only avro's flatten attribute and this will lead to problems.
   WDYT ?
   
   This could be done in a follow-up PR!



##########
avro_derive/src/lib.rs:
##########
@@ -142,26 +144,46 @@ fn get_data_struct_schema_def(
     let mut record_field_exprs = vec![];
     match s.fields {
         syn::Fields::Named(ref a) => {
-            let mut index: usize = 0;
             for field in a.named.iter() {
-                let mut name = field.ident.as_ref().unwrap().to_string(); // 
we know everything has a name
+                let mut name = field
+                    .ident
+                    .as_ref()
+                    .expect("Field must have a name")
+                    .to_string();
                 if let Some(raw_name) = name.strip_prefix("r#") {
                     name = raw_name.to_string();
                 }
                 let field_attrs =
-                    
FieldOptions::from_attributes(&field.attrs[..]).map_err(darling_to_syn)?;
+                    
FieldOptions::from_attributes(&field.attrs).map_err(darling_to_syn)?;
                 let doc =
                     preserve_optional(field_attrs.doc.or_else(|| 
extract_outer_doc(&field.attrs)));
                 match (field_attrs.rename, rename_all) {
                     (Some(rename), _) => {
                         name = rename;
                     }
-                    (None, rename_all) if !matches!(rename_all, 
RenameRule::None) => {
+                    (None, rename_all) if rename_all != RenameRule::None => {
                         name = rename_all.apply_to_field(&name);
                     }
                     _ => {}
                 }
-                if let Some(true) = field_attrs.skip {
+                if Some(true) == field_attrs.skip {
+                    continue;
+                } else if Some(true) == field_attrs.flatten {
+                    // Inline the fields of the child record at runtime, as we 
don't have access to
+                    // the schema here.
+                    let flatten_ty = &field.ty;
+                    record_field_exprs.push(quote! {
+                        if let 
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema { 
fields, .. }) = #flatten_ty::get_schema() {
+                            for mut field in fields {
+                                field.position = schema_fields.len();
+                                schema_fields.push(field)
+                            }
+                        } else {
+                            panic!("Can only flatten RecordSchema")

Review Comment:
   Let's print the non-RecordSchema for easier debugging.



##########
avro_derive/tests/derive.rs:
##########
@@ -1686,4 +1686,103 @@ mod test_derive {
             panic!("Unexpected schema type for Foo")
         }
     }
+
+    #[test]
+    fn avro_247_serde_flatten_support() {
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Nested {
+            a: bool,
+        }
+
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Foo {
+            #[serde(flatten)]
+            #[avro(flatten)]
+            nested: Nested,
+            b: i32,
+        }
+
+        let schema = r#"
+        {
+            "type":"record",
+            "name":"Foo",
+            "fields": [
+                {
+                    "name":"a",
+                    "type":"boolean"
+                },
+                {
+                    "name":"b",
+                    "type":"int"
+                }
+            ]
+        }
+        "#;
+
+        let schema = Schema::parse_str(schema).unwrap();
+        let derived_schema = Foo::get_schema();
+        if let Schema::Record(RecordSchema { name, fields, .. }) = 
&derived_schema {
+            assert_eq!("Foo", name.fullname(None));
+            for field in fields {
+                match field.name.as_str() {
+                    "a" | "b" => (), // expected
+                    name => panic!("Unexpected field name '{name}'"),
+                }
+            }
+        } else {
+            panic!("Foo schema must be a record schema: {derived_schema:?}")
+        }
+        assert_eq!(schema, derived_schema);
+
+        serde_assert(Foo {
+            nested: Nested { a: true },
+            b: 321,
+        });
+    }
+
+    #[test]
+    fn avro_247_serde_nested_flatten_support() {
+        use apache_avro::{AvroSchema, Reader, Writer, from_value};
+        use serde::{Deserialize, Serialize};
+
+        #[derive(AvroSchema, Serialize, Deserialize, PartialEq, Debug)]
+        pub struct NestedFoo {
+            one: u32,
+        }
+
+        #[derive(AvroSchema, Debug, Serialize, Deserialize, PartialEq)]
+        pub struct Foo {
+            #[serde(flatten)]
+            #[avro(flatten)]
+            nested_foo: NestedFoo,
+        }
+
+        #[derive(AvroSchema, Serialize, Debug, Deserialize, PartialEq)]
+        struct Bar {
+            foo: Foo,
+            two: u32,
+        }
+
+        let bar = Bar {
+            foo: Foo {
+                nested_foo: NestedFoo { one: 42 },
+            },
+            two: 2,
+            // test_enum: TestEnum::B,
+        };
+
+        let schema = Bar::get_schema();

Review Comment:
   IMO it would be nice to assert the generated schema here too.



##########
avro/src/serde/ser_schema.rs:
##########
@@ -420,6 +425,50 @@ impl<W: Write> ser::SerializeStruct for 
SchemaAwareWriteSerializeStruct<'_, '_,
     }
 }
 
+impl<W: Write> ser::SerializeMap for SchemaAwareWriteSerializeStruct<'_, '_, 
W> {

Review Comment:
   Please add a comment/docstring explaining when this impl is being used, i.e. 
for the flattening support.



##########
avro_derive/tests/derive.rs:
##########
@@ -1686,4 +1686,103 @@ mod test_derive {
             panic!("Unexpected schema type for Foo")
         }
     }
+
+    #[test]
+    fn avro_247_serde_flatten_support() {
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Nested {
+            a: bool,
+        }
+
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Foo {
+            #[serde(flatten)]
+            #[avro(flatten)]
+            nested: Nested,
+            b: i32,
+        }
+
+        let schema = r#"
+        {
+            "type":"record",
+            "name":"Foo",
+            "fields": [
+                {
+                    "name":"a",
+                    "type":"boolean"
+                },
+                {
+                    "name":"b",
+                    "type":"int"
+                }
+            ]
+        }
+        "#;
+
+        let schema = Schema::parse_str(schema).unwrap();
+        let derived_schema = Foo::get_schema();
+        if let Schema::Record(RecordSchema { name, fields, .. }) = 
&derived_schema {
+            assert_eq!("Foo", name.fullname(None));
+            for field in fields {
+                match field.name.as_str() {
+                    "a" | "b" => (), // expected
+                    name => panic!("Unexpected field name '{name}'"),
+                }
+            }
+        } else {
+            panic!("Foo schema must be a record schema: {derived_schema:?}")
+        }
+        assert_eq!(schema, derived_schema);
+
+        serde_assert(Foo {
+            nested: Nested { a: true },
+            b: 321,
+        });
+    }
+
+    #[test]
+    fn avro_247_serde_nested_flatten_support() {
+        use apache_avro::{AvroSchema, Reader, Writer, from_value};
+        use serde::{Deserialize, Serialize};
+
+        #[derive(AvroSchema, Serialize, Deserialize, PartialEq, Debug)]
+        pub struct NestedFoo {
+            one: u32,
+        }
+
+        #[derive(AvroSchema, Debug, Serialize, Deserialize, PartialEq)]
+        pub struct Foo {
+            #[serde(flatten)]
+            #[avro(flatten)]
+            nested_foo: NestedFoo,
+        }
+
+        #[derive(AvroSchema, Serialize, Debug, Deserialize, PartialEq)]
+        struct Bar {
+            foo: Foo,
+            two: u32,
+        }
+
+        let bar = Bar {
+            foo: Foo {
+                nested_foo: NestedFoo { one: 42 },
+            },
+            two: 2,
+            // test_enum: TestEnum::B,
+        };
+
+        let schema = Bar::get_schema();
+        println!("Generated schema: {:#?}", schema);

Review Comment:
   debug leftover



##########
avro_derive/tests/derive.rs:
##########
@@ -1686,4 +1686,103 @@ mod test_derive {
             panic!("Unexpected schema type for Foo")
         }
     }
+
+    #[test]
+    fn avro_247_serde_flatten_support() {
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Nested {
+            a: bool,
+        }
+
+        #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+        struct Foo {
+            #[serde(flatten)]
+            #[avro(flatten)]
+            nested: Nested,
+            b: i32,
+        }
+
+        let schema = r#"
+        {
+            "type":"record",
+            "name":"Foo",
+            "fields": [
+                {
+                    "name":"a",
+                    "type":"boolean"
+                },
+                {
+                    "name":"b",
+                    "type":"int"
+                }
+            ]
+        }
+        "#;
+
+        let schema = Schema::parse_str(schema).unwrap();
+        let derived_schema = Foo::get_schema();
+        if let Schema::Record(RecordSchema { name, fields, .. }) = 
&derived_schema {
+            assert_eq!("Foo", name.fullname(None));
+            for field in fields {
+                match field.name.as_str() {
+                    "a" | "b" => (), // expected
+                    name => panic!("Unexpected field name '{name}'"),
+                }
+            }
+        } else {
+            panic!("Foo schema must be a record schema: {derived_schema:?}")
+        }
+        assert_eq!(schema, derived_schema);
+
+        serde_assert(Foo {
+            nested: Nested { a: true },
+            b: 321,
+        });
+    }
+
+    #[test]
+    fn avro_247_serde_nested_flatten_support() {
+        use apache_avro::{AvroSchema, Reader, Writer, from_value};
+        use serde::{Deserialize, Serialize};
+
+        #[derive(AvroSchema, Serialize, Deserialize, PartialEq, Debug)]
+        pub struct NestedFoo {
+            one: u32,
+        }
+
+        #[derive(AvroSchema, Debug, Serialize, Deserialize, PartialEq)]
+        pub struct Foo {
+            #[serde(flatten)]
+            #[avro(flatten)]
+            nested_foo: NestedFoo,
+        }
+
+        #[derive(AvroSchema, Serialize, Debug, Deserialize, PartialEq)]
+        struct Bar {
+            foo: Foo,
+            two: u32,
+        }
+
+        let bar = Bar {
+            foo: Foo {
+                nested_foo: NestedFoo { one: 42 },
+            },
+            two: 2,
+            // test_enum: TestEnum::B,
+        };
+
+        let schema = Bar::get_schema();
+        println!("Generated schema: {:#?}", schema);
+
+        // When appending a value, use this crate's special extension method
+        let mut writer = Writer::new(&schema, Vec::new()).unwrap();
+        writer.append_ser(&bar).unwrap();
+
+        // Check that it was correctly serialized and is deserializable
+        let encoded = writer.into_inner().unwrap();
+        let mut reader = Reader::new(&encoded[..]).unwrap();
+        let value = reader.next().unwrap().unwrap();
+        let result: Bar = from_value(&value).unwrap();
+        assert_eq!(result, bar);
+    }

Review Comment:
   Ideas for more tests:
   * conflicting names in the outer struct and in the Nested/flatten one
   * `skip` attribute on a flattened field
   * empty flattened struct



##########
avro/src/serde/util.rs:
##########
@@ -0,0 +1,298 @@
+use crate::{Error, error::Details};
+use serde::{
+    Serialize, Serializer,
+    ser::{
+        SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, 
SerializeTuple,
+        SerializeTupleStruct, SerializeTupleVariant,
+    },
+};
+
+/// Serialize a `T: Serialize` as a `String`.
+///
+/// An error will be returned if any other function than 
[`Serializer::serialize_str`] is called.
+pub struct StringSerializer;
+
+impl Serializer for StringSerializer {
+    type Ok = String;
+    type Error = Error;
+    type SerializeSeq = Self;
+    type SerializeTuple = Self;
+    type SerializeTupleStruct = Self;
+    type SerializeTupleVariant = Self;
+    type SerializeMap = Self;
+    type SerializeStruct = Self;
+    type SerializeStructVariant = Self;
+
+    fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
+        Ok(v.to_string())
+    }
+
+    fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_some<T>(self, _value: &T) -> Result<Self::Ok, Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, 
Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_unit_variant(
+        self,
+        _name: &'static str,
+        _variant_index: u32,
+        _variant: &'static str,
+    ) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_newtype_struct<T>(
+        self,
+        _name: &'static str,
+        _value: &T,
+    ) -> Result<Self::Ok, Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_newtype_variant<T>(
+        self,
+        _name: &'static str,
+        _variant_index: u32,
+        _variant: &'static str,
+        _value: &T,
+    ) -> Result<Self::Ok, Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, 
Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, 
Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_tuple_struct(
+        self,
+        _name: &'static str,
+        _len: usize,
+    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_tuple_variant(
+        self,
+        _name: &'static str,
+        _variant_index: u32,
+        _variant: &'static str,
+        _len: usize,
+    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, 
Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_struct(
+        self,
+        _name: &'static str,
+        _len: usize,
+    ) -> Result<Self::SerializeStruct, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_struct_variant(
+        self,
+        _name: &'static str,
+        _variant_index: u32,
+        _variant: &'static str,
+        _len: usize,
+    ) -> Result<Self::SerializeStructVariant, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+}
+
+impl SerializeSeq for StringSerializer {
+    type Ok = String;
+    type Error = Error;
+
+    fn serialize_element<T>(&mut self, _value: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn end(self) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+}
+
+impl SerializeTuple for StringSerializer {
+    type Ok = String;
+    type Error = Error;
+
+    fn serialize_element<T>(&mut self, _value: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn end(self) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+}
+
+impl SerializeTupleStruct for StringSerializer {
+    type Ok = String;
+    type Error = Error;
+
+    fn serialize_field<T>(&mut self, _value: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn end(self) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+}
+
+impl SerializeTupleVariant for StringSerializer {
+    type Ok = String;
+    type Error = Error;
+
+    fn serialize_field<T>(&mut self, _value: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn end(self) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+}
+
+impl SerializeMap for StringSerializer {
+    type Ok = String;
+    type Error = Error;
+
+    fn serialize_key<T>(&mut self, _key: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn serialize_value<T>(&mut self, _value: &T) -> Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn end(self) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+}
+impl SerializeStruct for StringSerializer {
+    type Ok = String;
+    type Error = Error;
+
+    fn serialize_field<T>(&mut self, _key: &'static str, _value: &T) -> 
Result<(), Self::Error>
+    where
+        T: ?Sized + Serialize,
+    {
+        Err(Details::MapFieldExpectedString.into())
+    }
+
+    fn end(self) -> Result<Self::Ok, Self::Error> {
+        Err(Details::MapFieldExpectedString.into())
+    }
+}

Review Comment:
   ```suggestion
   }
   
   ```



##########
avro/src/serde/ser_schema.rs:
##########
@@ -1532,6 +1619,9 @@ impl<'s, W: Write> SchemaAwareWriteSerializer<'s, W> {
                     "Expected a Map schema in {union_schema:?}"
                 )))
             }
+            Schema::Record(record_schema) => 
Ok(SchemaAwareWriteSerializeMapOrStruct::Struct(
+                SchemaAwareWriteSerializeStruct::new(self, record_schema),
+            )),

Review Comment:
   Do we need a branch for `Schema::Ref` too ?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to