You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by kr...@apache.org on 2026/03/11 14:01:38 UTC

(avro-rs) 03/08: more testing

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

kriskras99 pushed a commit to branch feat/enums
in repository https://gitbox.apache.org/repos/asf/avro-rs.git

commit 51a68c4c4da664741eb241325fff1f8c2f3dd91e
Author: default <ad...@kriskras99.nl>
AuthorDate: Thu Mar 5 19:57:24 2026 +0000

    more testing
---
 avro_derive/src/attributes/mod.rs                  |  29 ++-
 avro_derive/src/enums/bare_union.rs                |  51 +---
 avro_derive/src/enums/record_internally_tagged.rs  |  32 ++-
 avro_derive/src/enums/record_tag_content.rs        |  52 +----
 avro_derive/src/enums/union_of_records.rs          |  64 ++----
 avro_derive/src/lib.rs                             | 228 +++++++++---------
 avro_derive/src/tuple.rs                           |  72 ++++++
 .../avro_3709_record_field_attributes.expanded.rs  | 131 +++++++----
 .../avro_rs_207_rename_all_attribute.expanded.rs   | 127 ++++++----
 ...name_attr_over_rename_all_attribute.expanded.rs | 127 ++++++----
 .../tests/expanded/avro_rs_501_basic.expanded.rs   | 127 ++++++----
 .../expanded/avro_rs_501_namespace.expanded.rs     | 127 ++++++----
 .../expanded/avro_rs_501_reference.expanded.rs     | 143 +++++++-----
 .../avro_rs_501_struct_with_optional.expanded.rs   |  85 ++++---
 .../expanded/avro_rs_xxx_bare_union.expanded.rs    | 256 +++++++++++++++++++++
 .../avro_rs_xxx_bare_union.rs}                     |  22 +-
 ...s => avro_rs_xxx_internally_tagged.expanded.rs} | 127 ++++++----
 ...sparent.rs => avro_rs_xxx_internally_tagged.rs} |   0
 .../avro_rs_xxx_serde_from_into.expanded.rs        | 139 ++++++-----
 .../avro_rs_xxx_serde_transparent.expanded.rs      | 153 ++++++++----
 .../expanded/avro_rs_xxx_serde_transparent.rs      |   6 +-
 ...nded.rs => avro_rs_xxx_tag_content.expanded.rs} | 127 ++++++----
 ...e_transparent.rs => avro_rs_xxx_tag_content.rs} |   0
 ...rs => avro_rs_xxx_union_of_records.expanded.rs} | 127 ++++++----
 ...nsparent.rs => avro_rs_xxx_union_of_records.rs} |   0
 avro_derive/tests/expanded/mod.rs                  |   4 +
 .../tests/ui/avro_rs_501_non_basic_enum.stderr     |  46 ----
 avro_derive/tests/ui/avro_rs_501_tuple_struct.rs   |  23 --
 .../tests/ui/avro_rs_501_tuple_struct.stderr       |   5 -
 .../tests/ui/avro_rs_501_unit_struct.stderr        |   5 -
 ...m.rs => avro_rs_xxx_bare_union_and_untagged.rs} |  23 +-
 .../ui/avro_rs_xxx_bare_union_and_untagged.stderr  |  20 ++
 .../ui/avro_rs_xxx_serde_transparent_enum.stderr   |   8 +
 33 files changed, 1540 insertions(+), 946 deletions(-)

diff --git a/avro_derive/src/attributes/mod.rs b/avro_derive/src/attributes/mod.rs
index 21fe772..3a35f3c 100644
--- a/avro_derive/src/attributes/mod.rs
+++ b/avro_derive/src/attributes/mod.rs
@@ -15,11 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::case::RenameRule;
+use crate::{case::RenameRule, type_to_field_default_expr};
 use darling::{FromAttributes, FromMeta};
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
-use syn::{AttrStyle, Attribute, Expr, Ident, Path, spanned::Spanned};
+use syn::{AttrStyle, Attribute, Expr, Ident, Path, Type, spanned::Spanned};
 
 mod avro;
 mod serde;
@@ -389,6 +389,31 @@ pub enum FieldDefault {
     Value(String),
 }
 
+impl FieldDefault {
+    pub fn into_tokenstream(
+        self,
+        span: Span,
+        field_type: &Type,
+    ) -> Result<TokenStream, Vec<syn::Error>> {
+        match self {
+            FieldDefault::Disabled => Ok(quote! { None }),
+            FieldDefault::Trait => type_to_field_default_expr(field_type),
+            FieldDefault::Value(default_value) => {
+                let _: serde_json::Value =
+                    serde_json::from_str(&default_value[..]).map_err(|e| {
+                        vec![syn::Error::new(
+                            span,
+                            format!("Invalid avro default json: \n{e}"),
+                        )]
+                    })?;
+                Ok(quote! {
+                    Some(::serde_json::from_str(#default_value).expect(format!("Invalid JSON: {:?}", #default_value).as_str()))
+                })
+            }
+        }
+    }
+}
+
 impl FromMeta for FieldDefault {
     fn from_string(value: &str) -> darling::Result<Self> {
         Ok(Self::Value(value.to_string()))
diff --git a/avro_derive/src/enums/bare_union.rs b/avro_derive/src/enums/bare_union.rs
index b0342b2..75cb558 100644
--- a/avro_derive/src/enums/bare_union.rs
+++ b/avro_derive/src/enums/bare_union.rs
@@ -1,5 +1,6 @@
 use crate::attributes::{NamedTypeOptions, VariantOptions};
-use crate::type_to_schema_expr;
+use crate::tuple::tuple_to_record_schema;
+use crate::{named_to_record_fields, type_to_schema_expr};
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
 use syn::spanned::Spanned;
@@ -13,36 +14,26 @@ pub fn get_data_enum_schema_def(
     let mut variant_expr = Vec::new();
     let mut have_null = false;
     for variant in data_enum.variants {
-        let field_attrs = VariantOptions::new(&variant.attrs, variant.span())?;
-        let name = field_attrs.rename.unwrap_or_else(|| {
+        let variant_attrs = VariantOptions::new(&variant.attrs, variant.span())?;
+        let name = variant_attrs.rename.unwrap_or_else(|| {
             container_attrs
                 .rename_all
                 .apply_to_variant(&variant.ident.to_string())
         });
         match variant.fields {
             Fields::Named(named) => {
-                let mut fields = Vec::with_capacity(named.named.len());
-                for field in named.named {
-                    let ident = field_attrs
+                let fields = named_to_record_fields(
+                    named,
+                    variant_attrs
                         .rename_all
-                        .or(container_attrs.rename_all_fields)
-                        .apply_to_field(&field.ident.unwrap().to_string());
-                    let schema_expr = type_to_schema_expr(&field.ty)?;
-                    fields.push(quote! {
-                        ::apache_avro::schema::RecordField::builder()
-                            .name(#ident.to_string())
-                            .schema(#schema_expr)
-                            .build()
-                    });
-                }
+                        .or(container_attrs.rename_all_fields),
+                )?;
 
                 let schema_expr = quote! {
                     ::apache_avro::schema::Schema::Record(
                         ::apache_avro::schema::RecordSchema::builder()
                             .name(::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(&format!("Unable to parse variant record name for schema {}", #name)[..]))
-                            .fields(vec![
-                                #(#fields,)*
-                            ])
+                            .fields(#fields)
                             .build()
                     )
                 };
@@ -59,28 +50,8 @@ pub fn get_data_enum_schema_def(
                     let schema_expr = type_to_schema_expr(&only_one.ty)?;
                     variant_expr.push(schema_expr);
                 } else if unnamed.unnamed.len() > 1 {
-                    let mut fields = Vec::with_capacity(unnamed.unnamed.len());
-                    for (index, field) in unnamed.unnamed.iter().enumerate() {
-                        let field_schema_expr = type_to_schema_expr(&field.ty)?;
-                        fields.push(quote! {
-                            ::apache_avro::schema::RecordField::builder()
-                                .name(format!("field_{}", #index))
-                                .schema(#field_schema_expr)
-                                .build()
-                        });
-                    }
+                    let schema_expr = tuple_to_record_schema(unnamed, &name, &[])?;
 
-                    let schema_expr = quote! {
-                        ::apache_avro::schema::Schema::Record(
-                            ::apache_avro::schema::RecordSchema::builder()
-                                .name(::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(&format!("Unable to parse variant record name for schema {}", #name)[..]))
-                                .fields(vec![
-                                    #(#fields,)*
-                                ])
-                                .attributes([("org.apache.avro.rust.tuple".to_string(), ::serde_json::value::Value::Bool(true))].into())
-                                .build()
-                        )
-                    };
                     variant_expr.push(schema_expr);
                 }
             }
diff --git a/avro_derive/src/enums/record_internally_tagged.rs b/avro_derive/src/enums/record_internally_tagged.rs
index f3331dc..7d09b0d 100644
--- a/avro_derive/src/enums/record_internally_tagged.rs
+++ b/avro_derive/src/enums/record_internally_tagged.rs
@@ -1,5 +1,5 @@
 use crate::attributes::{NamedTypeOptions, VariantOptions};
-use crate::{aliases, preserve_optional, type_to_schema_expr};
+use crate::{aliases, named_to_record_fields, preserve_optional, type_to_schema_expr};
 use proc_macro2::TokenStream;
 use quote::quote;
 use syn::spanned::Spanned;
@@ -15,33 +15,31 @@ pub fn get_data_enum_schema_def(
     let mut symbols = Vec::new();
     let mut field_additions = Vec::new();
     for variant in data_enum.variants {
-        let field_attrs = VariantOptions::new(&variant.attrs, variant.span())?;
-        let name = field_attrs.rename.unwrap_or_else(|| {
+        let variant_attrs = VariantOptions::new(&variant.attrs, variant.span())?;
+        let name = variant_attrs.rename.unwrap_or_else(|| {
             container_attrs
                 .rename_all
                 .apply_to_variant(&variant.ident.to_string())
         });
         match variant.fields {
             Fields::Named(named) => {
-                for field in named.named {
-                    let ident = field_attrs
+                let named_fields = named_to_record_fields(
+                    named,
+                    variant_attrs
                         .rename_all
-                        .or(container_attrs.rename_all_fields)
-                        .apply_to_field(&field.ident.unwrap().to_string());
-                    let schema_expr = type_to_schema_expr(&field.ty)?;
-                    field_additions.push(quote! {
-                        fields.push(::apache_avro::schema::RecordField::builder()
-                            .name(#ident.to_string())
-                            .schema(#schema_expr)
-                            .build())
-                    });
-                }
+                        .or(container_attrs.rename_all_fields),
+                )?;
+                field_additions.push(quote! {
+                    fields.extend(#named_fields);
+                });
             }
             Fields::Unnamed(unnamed) => {
                 if unnamed.unnamed.len() == 1 {
                     let only_one = unnamed.unnamed.iter().next().expect("There is one");
                     let schema_expr = type_to_schema_expr(&only_one.ty)?;
-                    field_additions.push(schema_expr);
+                    field_additions.push(quote! {
+                        fields.push(#schema_expr);
+                    });
                 } else if unnamed.unnamed.len() > 1 {
                     return Err(vec![syn::Error::new(
                         unnamed.span(),
@@ -71,7 +69,7 @@ pub fn get_data_enum_schema_def(
         ::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema::builder()
             .name(name)
             .maybe_aliases(#enum_aliases)
-            .maybe_doc(#doc)
+            .doc(#doc)
             .fields(fields)
             .build()
         )
diff --git a/avro_derive/src/enums/record_tag_content.rs b/avro_derive/src/enums/record_tag_content.rs
index 5227de2..2565cc9 100644
--- a/avro_derive/src/enums/record_tag_content.rs
+++ b/avro_derive/src/enums/record_tag_content.rs
@@ -1,5 +1,6 @@
 use crate::attributes::{NamedTypeOptions, VariantOptions};
-use crate::{aliases, preserve_optional, type_to_schema_expr};
+use crate::tuple::tuple_to_record_schema;
+use crate::{aliases, named_to_record_fields, preserve_optional, type_to_schema_expr};
 use proc_macro2::TokenStream;
 use quote::quote;
 use syn::spanned::Spanned;
@@ -16,36 +17,26 @@ pub fn get_data_enum_schema_def(
     let mut symbols = Vec::new();
     let mut schema_definitions = Vec::new();
     for variant in data_enum.variants {
-        let field_attrs = VariantOptions::new(&variant.attrs, variant.span())?;
-        let name = field_attrs.rename.unwrap_or_else(|| {
+        let variant_attrs = VariantOptions::new(&variant.attrs, variant.span())?;
+        let name = variant_attrs.rename.unwrap_or_else(|| {
             container_attrs
                 .rename_all
                 .apply_to_variant(&variant.ident.to_string())
         });
         match variant.fields {
             Fields::Named(named) => {
-                let mut fields = Vec::with_capacity(named.named.len());
-                for field in named.named {
-                    let ident = field_attrs
+                let fields = named_to_record_fields(
+                    named,
+                    variant_attrs
                         .rename_all
-                        .or(container_attrs.rename_all_fields)
-                        .apply_to_field(&field.ident.unwrap().to_string());
-                    let schema_expr = type_to_schema_expr(&field.ty)?;
-                    fields.push(quote! {
-                        ::apache_avro::schema::RecordField::builder()
-                            .name(#ident.to_string())
-                            .schema(#schema_expr)
-                            .build()
-                    });
-                }
+                        .or(container_attrs.rename_all_fields),
+                )?;
 
                 let schema_expr = quote! {
                     ::apache_avro::schema::Schema::Record(
                         ::apache_avro::schema::RecordSchema::builder()
                             .name(::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(&format!("Unable to parse variant record name for schema {}", #name)[..]))
-                            .fields(vec![
-                                #(#fields,)*
-                            ])
+                            .fields(#fields)
                             .build()
                     )
                 };
@@ -62,27 +53,8 @@ pub fn get_data_enum_schema_def(
                     let field_schema_expr = type_to_schema_expr(&only_one.ty)?;
                     schema_definitions.push(field_schema_expr);
                 } else if unnamed.unnamed.len() > 1 {
-                    let mut fields = Vec::with_capacity(unnamed.unnamed.len());
-                    for (index, field) in unnamed.unnamed.iter().enumerate() {
-                        let field_schema_expr = type_to_schema_expr(&field.ty)?;
-                        fields.push(quote! {
-                            ::apache_avro::schema::RecordField::builder()
-                                .name(format!("field_{}", #index))
-                                .schema(#field_schema_expr)
-                                .build()
-                        });
-                    }
+                    let schema_expr = tuple_to_record_schema(unnamed, &name, &[])?;
 
-                    let schema_expr = quote! {
-                        ::apache_avro::schema::Schema::Record(
-                            ::apache_avro::schema::RecordSchema::builder()
-                                .name(::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(&format!("Unable to parse variant record name for schema {}", #name)[..]))
-                                .fields(vec![
-                                    #(#fields,)*
-                                ])
-                                .build()
-                        )
-                    };
                     schema_definitions.push(schema_expr);
                 }
             }
@@ -119,7 +91,7 @@ pub fn get_data_enum_schema_def(
         ::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema::builder()
             .name(name)
             .maybe_aliases(#enum_aliases)
-            .maybe_doc(#doc)
+            .doc(#doc)
             .fields(fields)
             .build()
         )
diff --git a/avro_derive/src/enums/union_of_records.rs b/avro_derive/src/enums/union_of_records.rs
index 4a68a0e..8786abc 100644
--- a/avro_derive/src/enums/union_of_records.rs
+++ b/avro_derive/src/enums/union_of_records.rs
@@ -1,5 +1,6 @@
 use crate::attributes::{NamedTypeOptions, VariantOptions};
-use crate::type_to_schema_expr;
+use crate::named_to_record_fields;
+use crate::tuple::tuple_to_record_schema;
 use proc_macro2::TokenStream;
 use quote::quote;
 use syn::spanned::Spanned;
@@ -11,69 +12,42 @@ pub fn get_data_enum_schema_def(
 ) -> Result<TokenStream, Vec<syn::Error>> {
     let mut variant_expr = Vec::new();
     for variant in data_enum.variants {
-        let field_attrs = VariantOptions::new(&variant.attrs, variant.span())?;
-        let name = field_attrs.rename.unwrap_or_else(|| {
+        let variant_attrs = VariantOptions::new(&variant.attrs, variant.span())?;
+        let name = variant_attrs.rename.unwrap_or_else(|| {
             container_attrs
                 .rename_all
                 .apply_to_variant(&variant.ident.to_string())
         });
         match variant.fields {
             Fields::Named(named) => {
-                let mut fields = Vec::with_capacity(named.named.len());
-                for field in named.named {
-                    let ident = field_attrs
+                let fields = named_to_record_fields(
+                    named,
+                    variant_attrs
                         .rename_all
-                        .or(container_attrs.rename_all_fields)
-                        .apply_to_field(&field.ident.unwrap().to_string());
-                    let schema_expr = type_to_schema_expr(&field.ty)?;
-                    fields.push(quote! {
-                        ::apache_avro::schema::RecordField::builder()
-                            .name(#ident.to_string())
-                            .schema(#schema_expr)
-                            .build()
-                    });
-                }
+                        .or(container_attrs.rename_all_fields),
+                )?;
 
                 let schema_expr = quote! {
                     ::apache_avro::schema::Schema::Record(
                         ::apache_avro::schema::RecordSchema::builder()
                             .name(::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(&format!("Unable to parse variant record name for schema {}", #name)[..]))
-                            .fields(vec![
-                                #(#fields,)*
-                            ])
+                            .fields(#fields)
                             .build()
                     )
                 };
                 variant_expr.push(schema_expr);
             }
             Fields::Unnamed(unnamed) => {
-                let mut fields = Vec::with_capacity(unnamed.unnamed.len());
-                for (index, field) in unnamed.unnamed.iter().enumerate() {
-                    let field_schema_expr = type_to_schema_expr(&field.ty)?;
-                    fields.push(quote! {
-                        ::apache_avro::schema::RecordField::builder()
-                            .name(format!("field_{}", #index))
-                            .schema(#field_schema_expr)
-                            .build()
-                    });
-                }
-
-                let amount_of_fields = unnamed.unnamed.len();
-
-                let schema_expr = quote! {
-                    let mut builder = ::apache_avro::schema::RecordSchema::builder()
-                            .name(::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(&format!("Unable to parse variant record name for schema {}", #name)[..]))
-                            .fields(vec![
-                                #(#fields,)*
-                            ]);
-                    if #amount_of_fields == 1 {
-                        builder = builder.attributes([("org.apache.avro.rust.union_of_records".to_string(), ::serde_json::value::Value::Bool(true))].into());
-                    } else if #amount_of_fields > 1 {
-                        builder = builder.attributes([("org.apache.avro.rust.tuple".to_string(), ::serde_json::value::Value::Bool(true))].into());
-                    }
-
-                    ::apache_avro::schema::Schema::Record(builder.build())
+                let schema_expr = if unnamed.unnamed.len() == 1 {
+                    tuple_to_record_schema(
+                        unnamed,
+                        &name,
+                        &["org.apache.avro.rust.union_of_records"],
+                    )?
+                } else {
+                    tuple_to_record_schema(unnamed, &name, &[])?
                 };
+
                 variant_expr.push(schema_expr);
             }
             Fields::Unit => {
diff --git a/avro_derive/src/lib.rs b/avro_derive/src/lib.rs
index 36836a4..e0e8217 100644
--- a/avro_derive/src/lib.rs
+++ b/avro_derive/src/lib.rs
@@ -32,17 +32,19 @@
 mod attributes;
 mod case;
 mod enums;
+mod tuple;
 
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
 use syn::{
-    DataStruct, DeriveInput, Expr, Field, Fields, Generics, Ident, Type, parse_macro_input,
-    spanned::Spanned,
+    DataStruct, DeriveInput, Expr, Field, Fields, FieldsNamed, Generics, Ident, Type,
+    parse_macro_input, spanned::Spanned,
 };
 
 use crate::{
-    attributes::{FieldDefault, FieldOptions, NamedTypeOptions, With},
+    attributes::{FieldOptions, NamedTypeOptions, With},
     case::RenameRule,
+    tuple::unnamed_to_record_fields,
 };
 
 #[proc_macro_derive(AvroSchema, attributes(avro, serde))]
@@ -81,11 +83,8 @@ fn derive_avro_schema(input: DeriveInput) -> Result<TokenStream, Vec<syn::Error>
                 let (get_schema_impl, get_record_fields_impl) = if named_type_options.transparent {
                     get_transparent_struct_schema_def(data_struct.fields, input_span)?
                 } else {
-                    let (schema_def, record_fields) = get_struct_schema_def(
-                        &named_type_options,
-                        data_struct,
-                        input.ident.span(),
-                    )?;
+                    let (schema_def, record_fields) =
+                        get_struct_schema_def(&named_type_options, data_struct)?;
                     (
                         handle_named_schemas(named_type_options.name, schema_def),
                         record_fields,
@@ -173,105 +172,20 @@ fn handle_named_schemas(full_schema_name: String, schema_def: TokenStream) -> To
 fn get_struct_schema_def(
     container_attrs: &NamedTypeOptions,
     data_struct: DataStruct,
-    ident_span: Span,
 ) -> Result<(TokenStream, TokenStream), Vec<syn::Error>> {
-    let mut record_field_exprs = vec![];
-    match data_struct.fields {
-        Fields::Named(a) => {
-            for field in a.named {
-                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::new(&field.attrs, field.span())?;
-                let doc = preserve_optional(field_attrs.doc);
-                match (field_attrs.rename, container_attrs.rename_all) {
-                    (Some(rename), _) => {
-                        name = rename;
-                    }
-                    (None, rename_all) if rename_all != RenameRule::None => {
-                        name = rename_all.apply_to_field(&name);
-                    }
-                    _ => {}
-                }
-                if field_attrs.skip {
-                    continue;
-                } else if field_attrs.flatten {
-                    // Inline the fields of the child record at runtime, as we don't have access to
-                    // the schema here.
-                    let get_record_fields =
-                        get_field_get_record_fields_expr(&field, field_attrs.with)?;
-                    record_field_exprs.push(quote! {
-                        if let Some(flattened_fields) = #get_record_fields {
-                            schema_fields.extend(flattened_fields);
-                        } else {
-                            panic!("{} does not have any fields to flatten to", stringify!(#field));
-                        }
-                    });
-
-                    // Don't add this field as it's been replaced by the child record fields
-                    continue;
-                }
-                let default_value = match field_attrs.default {
-                    FieldDefault::Disabled => quote! { ::std::option::Option::None },
-                    FieldDefault::Trait => type_to_field_default_expr(&field.ty)?,
-                    FieldDefault::Value(default_value) => {
-                        let _: serde_json::Value = serde_json::from_str(&default_value[..])
-                            .map_err(|e| {
-                                vec![syn::Error::new(
-                                    field.ident.span(),
-                                    format!("Invalid avro default json: \n{e}"),
-                                )]
-                            })?;
-                        quote! {
-                            ::std::option::Option::Some(::serde_json::from_str(#default_value).expect("Unreachable! This parsed at compile time!"))
-                        }
-                    }
-                };
-                let aliases = field_aliases(&field_attrs.alias);
-                let schema_expr = get_field_schema_expr(&field, field_attrs.with)?;
-                record_field_exprs.push(quote! {
-                    schema_fields.push(::apache_avro::schema::RecordField {
-                        name: #name.to_string(),
-                        doc: #doc,
-                        default: #default_value,
-                        aliases: #aliases,
-                        schema: #schema_expr,
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                });
-            }
-        }
-        Fields::Unnamed(_) => {
-            return Err(vec![syn::Error::new(
-                ident_span,
-                "AvroSchema derive does not work for tuple structs",
-            )]);
-        }
-        Fields::Unit => {
-            return Err(vec![syn::Error::new(
-                ident_span,
-                "AvroSchema derive does not work for unit structs",
-            )]);
-        }
-    }
+    let record_fields = match data_struct.fields {
+        Fields::Named(a) => named_to_record_fields(a, container_attrs.rename_all)?,
+        Fields::Unnamed(unnamed) => unnamed_to_record_fields(unnamed)?,
+        Fields::Unit => quote! { std::vec::Vec::<::apache_avro::schema::RecordField>::new() },
+    };
 
     let record_doc = preserve_optional(container_attrs.doc.as_ref());
     let record_aliases = aliases(&container_attrs.aliases);
     let full_schema_name = &container_attrs.name;
 
-    // When flatten is involved, there will be more but we don't know how many. This optimises for
-    // the most common case where there is no flatten.
-    let minimum_fields = record_field_exprs.len();
-
     let schema_def = quote! {
         {
-            let mut schema_fields = ::std::vec::Vec::with_capacity(#minimum_fields);
-            #(#record_field_exprs)*
+            let schema_fields = #record_fields;
             let schema_field_set: ::std::collections::HashSet<_> = schema_fields.iter().map(|rf| &rf.name).collect();
             assert_eq!(schema_fields.len(), schema_field_set.len(), "Duplicate field names found: {schema_fields:?}");
             let name = ::apache_avro::schema::Name::new(#full_schema_name).expect(&format!("Unable to parse struct name for schema {}", #full_schema_name)[..]);
@@ -291,9 +205,7 @@ fn get_struct_schema_def(
         }
     };
     let record_fields = quote! {
-        let mut schema_fields = ::std::vec::Vec::with_capacity(#minimum_fields);
-        #(#record_field_exprs)*
-        ::std::option::Option::Some(schema_fields)
+        ::std::option::Option::Some(#record_fields)
     };
 
     Ok((schema_def, record_fields))
@@ -332,13 +244,36 @@ fn get_transparent_struct_schema_def(
                 )])
             }
         }
-        Fields::Unnamed(_) => Err(vec![syn::Error::new(
-            input_span,
-            "AvroSchema: derive does not work for tuple structs",
-        )]),
+        Fields::Unnamed(unnamed) => {
+            let mut found = None;
+            for field in unnamed.unnamed {
+                let attrs = FieldOptions::new(&field.attrs, field.span())?;
+                if attrs.skip {
+                    continue;
+                }
+                if found.replace((field, attrs)).is_some() {
+                    return Err(vec![syn::Error::new(
+                        input_span,
+                        "AvroSchema: #[serde(transparent)] is only allowed on structs with one unskipped field",
+                    )]);
+                }
+            }
+
+            if let Some((field, attrs)) = found {
+                Ok((
+                    get_field_schema_expr(&field, attrs.with.clone())?,
+                    get_field_get_record_fields_expr(&field, attrs.with)?,
+                ))
+            } else {
+                Err(vec![syn::Error::new(
+                    input_span,
+                    "AvroSchema: #[serde(transparent)] is only allowed on structs with one unskipped field",
+                )])
+            }
+        }
         Fields::Unit => Err(vec![syn::Error::new(
             input_span,
-            "AvroSchema: derive does not work for unit structs",
+            "AvroSchema: `#[serde(transparent)` does not work for unit structs",
         )]),
     }
 }
@@ -469,6 +404,78 @@ fn type_to_field_default_expr(ty: &Type) -> Result<TokenStream, Vec<syn::Error>>
     }
 }
 
+/// Create a vector of `RecordField`s.
+fn named_to_record_fields(
+    named: FieldsNamed,
+    rename_all: RenameRule,
+) -> Result<TokenStream, Vec<syn::Error>> {
+    let mut fields = Vec::with_capacity(named.named.len());
+    for field in named.named {
+        let field_attrs = FieldOptions::new(&field.attrs, field.span())?;
+        if field_attrs.skip {
+            continue;
+        } else if field_attrs.flatten {
+            // Inline the fields of the child record at runtime, as we don't have access to
+            // the schema here.
+            let get_record_fields = get_field_get_record_fields_expr(&field, field_attrs.with)?;
+            fields.push(quote! {
+                if let Some(flattened_fields) = #get_record_fields {
+                    fields.extend(flattened_fields);
+                } else {
+                    panic!("{} does not have any fields to flatten to", stringify!(#field));
+                }
+            });
+
+            // Don't add this field as it's been replaced by the child record fields
+            continue;
+        }
+        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();
+        }
+        match (field_attrs.rename, rename_all) {
+            (Some(rename), _) => {
+                name = rename;
+            }
+            (None, rename_all) if rename_all != RenameRule::None => {
+                name = rename_all.apply_to_field(&name);
+            }
+            _ => {}
+        }
+        let default_value = field_attrs
+            .default
+            .into_tokenstream(field.ident.span(), &field.ty)?;
+        let aliases = field_aliases(&field_attrs.alias);
+        let doc = doc_into_tokenstream(field_attrs.doc);
+        let field_schema_expr = get_field_schema_expr(&field, field_attrs.with)?;
+        fields.push(quote! {
+            fields.push(::apache_avro::schema::RecordField::builder()
+                .name(#name.to_string())
+                .doc(#doc)
+                .maybe_default(#default_value)
+                .aliases(#aliases)
+                .schema(#field_schema_expr)
+                .build());
+        });
+    }
+
+    // When fields are flattened there might be more fields, but this is good for the regular case
+    let minimum_length = fields.len();
+    Ok(quote! {
+        {
+            let mut fields = ::std::vec::Vec::with_capacity(#minimum_length);
+            #(
+                #fields
+            )*
+            fields
+        }
+    })
+}
+
 /// Stolen from serde
 fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
     let compile_errors = errors.iter().map(syn::Error::to_compile_error);
@@ -482,6 +489,13 @@ fn preserve_optional(op: Option<impl quote::ToTokens>) -> TokenStream {
     }
 }
 
+fn doc_into_tokenstream(doc: Option<String>) -> TokenStream {
+    match doc {
+        Some(doc) => quote! {::std::option::Option::Some(#doc.to_string())},
+        None => quote! {::std::option::Option::None},
+    }
+}
+
 fn aliases(op: &[impl quote::ToTokens]) -> TokenStream {
     let items: Vec<TokenStream> = op
         .iter()
diff --git a/avro_derive/src/tuple.rs b/avro_derive/src/tuple.rs
new file mode 100644
index 0000000..387bee5
--- /dev/null
+++ b/avro_derive/src/tuple.rs
@@ -0,0 +1,72 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{FieldsUnnamed, spanned::Spanned};
+
+use crate::{FieldOptions, doc_into_tokenstream, field_aliases, type_to_schema_expr};
+
+/// Create a `Schema::Record` from this tuple definition.
+///
+/// Fields are named `field_{field_index}` and the struct will have the provided name.
+///
+/// The schema will have the attribute `org.apache.avro.rust.tuple` any any other specified in `extra_attributes`.
+/// All attributes will have a value of `true`.
+pub fn tuple_to_record_schema(
+    unnamed: FieldsUnnamed,
+    name: &str,
+    extra_attributes: &[&str],
+) -> Result<TokenStream, Vec<syn::Error>> {
+    let fields = unnamed_to_record_fields(unnamed)?;
+
+    Ok(quote! {
+        ::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema::builder()
+            .name(::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(&format!("Unable to parse variant record name for schema {}", #name)[..]))
+            .fields(#fields)
+            .attributes(
+                [
+                    ("org.apache.avro.rust.tuple".to_string(), ::serde_json::value::Value::Bool(true)),
+                    #((#extra_attributes.to_string(), ::serde_json::value::Value::Bool(true)),)*
+                ].into()
+            )
+            .build()
+        )
+    })
+}
+
+/// Create a vector of `RecordField`s named `field_{field_index}`.
+pub fn unnamed_to_record_fields(unnamed: FieldsUnnamed) -> Result<TokenStream, Vec<syn::Error>> {
+    let mut fields = Vec::with_capacity(unnamed.unnamed.len());
+    for (index, field) in unnamed.unnamed.into_iter().enumerate() {
+        let field_attrs = FieldOptions::new(&field.attrs, field.span())?;
+        if field_attrs.skip {
+            continue;
+        } else if field_attrs.flatten {
+            return Err(vec![syn::Error::new(
+                field.span(),
+                "AvroSchema: `#[serde(flatten)]` is not supported on tuple fields",
+            )]);
+        }
+        let default_value = field_attrs
+            .default
+            .into_tokenstream(field.ident.span(), &field.ty)?;
+        let aliases = field_aliases(&field_attrs.alias);
+        let doc = doc_into_tokenstream(field_attrs.doc);
+        let name = field_attrs
+            .rename
+            .unwrap_or_else(|| format!("field_{index}"));
+        let field_schema_expr = type_to_schema_expr(&field.ty)?;
+        fields.push(quote! {
+            ::apache_avro::schema::RecordField::builder()
+                .name(#name.to_string())
+                .doc(#doc)
+                .maybe_default(#default_value)
+                .aliases(#aliases)
+                .schema(#field_schema_expr)
+                .build()
+        });
+    }
+    Ok(quote! {
+        vec![
+            #(#fields, )*
+        ]
+    })
+}
diff --git a/avro_derive/tests/expanded/avro_3709_record_field_attributes.expanded.rs b/avro_derive/tests/expanded/avro_3709_record_field_attributes.expanded.rs
index fab35a9..78f8992 100644
--- a/avro_derive/tests/expanded/avro_3709_record_field_attributes.expanded.rs
+++ b/avro_derive/tests/expanded/avro_3709_record_field_attributes.expanded.rs
@@ -24,30 +24,47 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(1usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a3".to_string(),
-                        doc: ::std::option::Option::Some("a doc".into()),
-                        default: ::std::option::Option::Some(
-                            ::serde_json::from_str("123")
-                                .expect("Unreachable! This parsed at compile time!"),
-                        ),
-                        aliases: ::alloc::boxed::box_assume_init_into_vec_unsafe(
-                            ::alloc::intrinsics::write_box_via_move(
-                                ::alloc::boxed::Box::new_uninit(),
-                                [
-                                    "a1".try_into().expect("Alias is invalid"),
-                                    "a2".try_into().expect("Alias is invalid"),
-                                ],
-                            ),
-                        ),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(1usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a3".to_string())
+                                .doc(::std::option::Option::Some("a doc".to_string()))
+                                .maybe_default(
+                                    Some(
+                                        ::serde_json::from_str("123")
+                                            .expect(
+                                                ::alloc::__export::must_use({
+                                                        ::alloc::fmt::format(
+                                                            format_args!("Invalid JSON: {0:?}", "123"),
+                                                        )
+                                                    })
+                                                    .as_str(),
+                                            ),
+                                    ),
+                                )
+                                .aliases(
+                                    ::alloc::boxed::box_assume_init_into_vec_unsafe(
+                                        ::alloc::intrinsics::write_box_via_move(
+                                            ::alloc::boxed::Box::new_uninit(),
+                                            [
+                                                "a1".try_into().expect("Alias is invalid"),
+                                                "a2".try_into().expect("Alias is invalid"),
+                                            ],
+                                        ),
+                                    ),
+                                )
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -99,31 +116,47 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = ::std::vec::Vec::with_capacity(1usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a3".to_string(),
-                doc: ::std::option::Option::Some("a doc".into()),
-                default: ::std::option::Option::Some(
-                    ::serde_json::from_str("123")
-                        .expect("Unreachable! This parsed at compile time!"),
-                ),
-                aliases: ::alloc::boxed::box_assume_init_into_vec_unsafe(
-                    ::alloc::intrinsics::write_box_via_move(
-                        ::alloc::boxed::Box::new_uninit(),
-                        [
-                            "a1".try_into().expect("Alias is invalid"),
-                            "a2".try_into().expect("Alias is invalid"),
-                        ],
-                    ),
-                ),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        ::std::option::Option::Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(1usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a3".to_string())
+                        .doc(::std::option::Option::Some("a doc".to_string()))
+                        .maybe_default(
+                            Some(
+                                ::serde_json::from_str("123")
+                                    .expect(
+                                        ::alloc::__export::must_use({
+                                                ::alloc::fmt::format(
+                                                    format_args!("Invalid JSON: {0:?}", "123"),
+                                                )
+                                            })
+                                            .as_str(),
+                                    ),
+                            ),
+                        )
+                        .aliases(
+                            ::alloc::boxed::box_assume_init_into_vec_unsafe(
+                                ::alloc::intrinsics::write_box_via_move(
+                                    ::alloc::boxed::Box::new_uninit(),
+                                    [
+                                        "a1".try_into().expect("Alias is invalid"),
+                                        "a2".try_into().expect("Alias is invalid"),
+                                    ],
+                                ),
+                            ),
+                        )
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.expanded.rs b/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.expanded.rs
index 0823ca7..d6fb135 100644
--- a/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.expanded.rs
@@ -23,31 +23,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "ITEM".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "DOUBLE_ITEM".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("ITEM".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("DOUBLE_ITEM".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -99,32 +112,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "ITEM".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "DOUBLE_ITEM".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        ::std::option::Option::Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("ITEM".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("DOUBLE_ITEM".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.expanded.rs b/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.expanded.rs
index 0689cb1..7363f61 100644
--- a/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.expanded.rs
@@ -24,31 +24,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "ITEM".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "DoubleItem".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("ITEM".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("DoubleItem".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -100,32 +113,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "ITEM".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "DoubleItem".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        ::std::option::Option::Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("ITEM".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("DoubleItem".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_501_basic.expanded.rs b/avro_derive/tests/expanded/avro_rs_501_basic.expanded.rs
index b2952df..b3ae37f 100644
--- a/avro_derive/tests/expanded/avro_rs_501_basic.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_501_basic.expanded.rs
@@ -22,31 +22,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "b".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("b".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -98,32 +111,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "b".to_string(),
-                doc: ::std::option::Option::None,
-                default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        ::std::option::Option::Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("b".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_501_namespace.expanded.rs b/avro_derive/tests/expanded/avro_rs_501_namespace.expanded.rs
index ce84a5d..9e06108 100644
--- a/avro_derive/tests/expanded/avro_rs_501_namespace.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_501_namespace.expanded.rs
@@ -23,31 +23,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "b".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("b".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -100,32 +113,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "b".to_string(),
-                doc: ::std::option::Option::None,
-                default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        ::std::option::Option::Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("b".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_501_reference.expanded.rs b/avro_derive/tests/expanded/avro_rs_501_reference.expanded.rs
index 9916d4f..24efb4c 100644
--- a/avro_derive/tests/expanded/avro_rs_501_reference.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_501_reference.expanded.rs
@@ -22,35 +22,48 @@ impl<'a> ::apache_avro::AvroSchemaComponent for A<'a> {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <&'a Vec<
-                            i32,
-                        > as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <&'a Vec<
-                            i32,
-                        > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "b".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <&'static str as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <&'static str as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <&'a Vec<
+                                        i32,
+                                    > as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <&'a Vec<
+                                        i32,
+                                    > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("b".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <&'static str as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <&'static str as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -102,36 +115,48 @@ impl<'a> ::apache_avro::AvroSchemaComponent for A<'a> {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <&'a Vec<
-                    i32,
-                > as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <&'a Vec<
-                    i32,
-                > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "b".to_string(),
-                doc: ::std::option::Option::None,
-                default: <&'static str as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <&'static str as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        ::std::option::Option::Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <&'a Vec<
+                                i32,
+                            > as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <&'a Vec<
+                                i32,
+                            > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("b".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <&'static str as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <&'static str as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.expanded.rs b/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.expanded.rs
index 076143e..0da6c5e 100644
--- a/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.expanded.rs
@@ -21,23 +21,31 @@ impl ::apache_avro::AvroSchemaComponent for TestOptional {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(1usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <Option<
-                            i32,
-                        > as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <Option<
-                            i32,
-                        > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(1usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <Option<
+                                        i32,
+                                    > as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <Option<
+                                        i32,
+                                    > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -90,24 +98,31 @@ impl ::apache_avro::AvroSchemaComponent for TestOptional {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = ::std::vec::Vec::with_capacity(1usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <Option<
-                    i32,
-                > as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <Option<
-                    i32,
-                > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        ::std::option::Option::Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(1usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <Option<
+                                i32,
+                            > as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <Option<
+                                i32,
+                            > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_bare_union.expanded.rs b/avro_derive/tests/expanded/avro_rs_xxx_bare_union.expanded.rs
new file mode 100644
index 0000000..e37481e
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_xxx_bare_union.expanded.rs
@@ -0,0 +1,256 @@
+use apache_avro::AvroSchema;
+#[serde(untagged)]
+enum Abc {
+    A,
+    B(bool),
+    C(#[avro(doc = "This is an int")] i32, i64),
+    D {},
+    E { is_it_true: bool },
+    F { #[avro(doc = "This is X")] x: f64, y: f32 },
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for Abc {
+    fn get_schema_in_ctxt(
+        named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
+        enclosing_namespace: ::apache_avro::schema::NamespaceRef,
+    ) -> ::apache_avro::schema::Schema {
+        let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+                "Abc",
+                enclosing_namespace,
+            )
+            .expect("Unable to parse schema name Abc");
+        if named_schemas.contains(&name) {
+            ::apache_avro::schema::Schema::Ref {
+                name,
+            }
+        } else {
+            let enclosing_namespace = name.namespace();
+            named_schemas.insert(name.clone());
+            let mut builder = ::apache_avro::schema::UnionSchema::builder();
+            builder
+                .variant(::apache_avro::schema::Schema::Null)
+                .expect("Duplicate Schema found");
+            builder
+                .variant(
+                    <bool as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                        named_schemas,
+                        enclosing_namespace,
+                    ),
+                )
+                .expect("Duplicate Schema found");
+            builder
+                .variant(
+                    ::apache_avro::schema::Schema::Record(
+                        ::apache_avro::schema::RecordSchema::builder()
+                            .name(
+                                ::apache_avro::schema::Name::new_with_enclosing_namespace(
+                                        "C",
+                                        enclosing_namespace,
+                                    )
+                                    .expect(
+                                        &::alloc::__export::must_use({
+                                            ::alloc::fmt::format(
+                                                format_args!(
+                                                    "Unable to parse variant record name for schema {0}", "C",
+                                                ),
+                                            )
+                                        })[..],
+                                    ),
+                            )
+                            .fields(
+                                ::alloc::boxed::box_assume_init_into_vec_unsafe(
+                                    ::alloc::intrinsics::write_box_via_move(
+                                        ::alloc::boxed::Box::new_uninit(),
+                                        [
+                                            ::apache_avro::schema::RecordField::builder()
+                                                .name("field_0".to_string())
+                                                .doc(
+                                                    ::std::option::Option::Some("This is an int".to_string()),
+                                                )
+                                                .maybe_default(
+                                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                                )
+                                                .aliases(::std::vec::Vec::new())
+                                                .schema(
+                                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                                        named_schemas,
+                                                        enclosing_namespace,
+                                                    ),
+                                                )
+                                                .build(),
+                                            ::apache_avro::schema::RecordField::builder()
+                                                .name("field_1".to_string())
+                                                .doc(::std::option::Option::None)
+                                                .maybe_default(
+                                                    <i64 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                                )
+                                                .aliases(::std::vec::Vec::new())
+                                                .schema(
+                                                    <i64 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                                        named_schemas,
+                                                        enclosing_namespace,
+                                                    ),
+                                                )
+                                                .build(),
+                                        ],
+                                    ),
+                                ),
+                            )
+                            .attributes(
+                                [
+                                    (
+                                        "org.apache.avro.rust.tuple".to_string(),
+                                        ::serde_json::value::Value::Bool(true),
+                                    ),
+                                ]
+                                    .into(),
+                            )
+                            .build(),
+                    ),
+                )
+                .expect("Duplicate Schema found");
+            builder
+                .variant(
+                    ::apache_avro::schema::Schema::Record(
+                        ::apache_avro::schema::RecordSchema::builder()
+                            .name(
+                                ::apache_avro::schema::Name::new_with_enclosing_namespace(
+                                        "D",
+                                        enclosing_namespace,
+                                    )
+                                    .expect(
+                                        &::alloc::__export::must_use({
+                                            ::alloc::fmt::format(
+                                                format_args!(
+                                                    "Unable to parse variant record name for schema {0}", "D",
+                                                ),
+                                            )
+                                        })[..],
+                                    ),
+                            )
+                            .fields({
+                                let mut fields = ::std::vec::Vec::with_capacity(0usize);
+                                fields
+                            })
+                            .build(),
+                    ),
+                )
+                .expect("Duplicate Schema found");
+            builder
+                .variant(
+                    ::apache_avro::schema::Schema::Record(
+                        ::apache_avro::schema::RecordSchema::builder()
+                            .name(
+                                ::apache_avro::schema::Name::new_with_enclosing_namespace(
+                                        "E",
+                                        enclosing_namespace,
+                                    )
+                                    .expect(
+                                        &::alloc::__export::must_use({
+                                            ::alloc::fmt::format(
+                                                format_args!(
+                                                    "Unable to parse variant record name for schema {0}", "E",
+                                                ),
+                                            )
+                                        })[..],
+                                    ),
+                            )
+                            .fields({
+                                let mut fields = ::std::vec::Vec::with_capacity(1usize);
+                                fields
+                                    .push(
+                                        ::apache_avro::schema::RecordField::builder()
+                                            .name("is_it_true".to_string())
+                                            .doc(::std::option::Option::None)
+                                            .maybe_default(
+                                                <bool as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                            )
+                                            .aliases(::std::vec::Vec::new())
+                                            .schema(
+                                                <bool as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                                    named_schemas,
+                                                    enclosing_namespace,
+                                                ),
+                                            )
+                                            .build(),
+                                    );
+                                fields
+                            })
+                            .build(),
+                    ),
+                )
+                .expect("Duplicate Schema found");
+            builder
+                .variant(
+                    ::apache_avro::schema::Schema::Record(
+                        ::apache_avro::schema::RecordSchema::builder()
+                            .name(
+                                ::apache_avro::schema::Name::new_with_enclosing_namespace(
+                                        "F",
+                                        enclosing_namespace,
+                                    )
+                                    .expect(
+                                        &::alloc::__export::must_use({
+                                            ::alloc::fmt::format(
+                                                format_args!(
+                                                    "Unable to parse variant record name for schema {0}", "F",
+                                                ),
+                                            )
+                                        })[..],
+                                    ),
+                            )
+                            .fields({
+                                let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                                fields
+                                    .push(
+                                        ::apache_avro::schema::RecordField::builder()
+                                            .name("x".to_string())
+                                            .doc(::std::option::Option::Some("This is X".to_string()))
+                                            .maybe_default(
+                                                <f64 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                            )
+                                            .aliases(::std::vec::Vec::new())
+                                            .schema(
+                                                <f64 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                                    named_schemas,
+                                                    enclosing_namespace,
+                                                ),
+                                            )
+                                            .build(),
+                                    );
+                                fields
+                                    .push(
+                                        ::apache_avro::schema::RecordField::builder()
+                                            .name("y".to_string())
+                                            .doc(::std::option::Option::None)
+                                            .maybe_default(
+                                                <f32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                            )
+                                            .aliases(::std::vec::Vec::new())
+                                            .schema(
+                                                <f32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                                    named_schemas,
+                                                    enclosing_namespace,
+                                                ),
+                                            )
+                                            .build(),
+                                    );
+                                fields
+                            })
+                            .build(),
+                    ),
+                )
+                .expect("Duplicate Schema found");
+            ::apache_avro::schema::Schema::Union(builder.build())
+        }
+    }
+    fn get_record_fields_in_ctxt(
+        named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
+        enclosing_namespace: ::apache_avro::schema::NamespaceRef,
+    ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
+        None
+    }
+    fn field_default() -> ::std::option::Option<::serde_json::Value> {
+        ::std::option::Option::None
+    }
+}
diff --git a/avro_derive/tests/ui/avro_rs_501_unit_struct.rs b/avro_derive/tests/expanded/avro_rs_xxx_bare_union.rs
similarity index 76%
rename from avro_derive/tests/ui/avro_rs_501_unit_struct.rs
rename to avro_derive/tests/expanded/avro_rs_xxx_bare_union.rs
index 1b740af..34a3c51 100644
--- a/avro_derive/tests/ui/avro_rs_501_unit_struct.rs
+++ b/avro_derive/tests/expanded/avro_rs_xxx_bare_union.rs
@@ -18,6 +18,22 @@
 use apache_avro::AvroSchema;
 
 #[derive(AvroSchema)]
-struct AbsoluteUnit;
-
-fn main() {}
+#[serde(untagged)]
+enum Abc {
+    A,
+    B(bool),
+    C(
+        #[avro(doc = "This is an int")]
+        i32, 
+        i64
+    ),
+    D {},
+    E {
+        is_it_true: bool,
+    },
+    F {
+        #[avro(doc = "This is X")]
+        x: f64,
+        y: f32,
+    }
+}
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs b/avro_derive/tests/expanded/avro_rs_xxx_internally_tagged.expanded.rs
similarity index 55%
copy from avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
copy to avro_derive/tests/expanded/avro_rs_xxx_internally_tagged.expanded.rs
index b85a630..d75f321 100644
--- a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_xxx_internally_tagged.expanded.rs
@@ -22,31 +22,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "b".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("b".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -98,32 +111,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "b".to_string(),
-                doc: ::std::option::Option::None,
-                default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("b".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs b/avro_derive/tests/expanded/avro_rs_xxx_internally_tagged.rs
similarity index 100%
copy from avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs
copy to avro_derive/tests/expanded/avro_rs_xxx_internally_tagged.rs
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_from_into.expanded.rs b/avro_derive/tests/expanded/avro_rs_xxx_serde_from_into.expanded.rs
index 83b87d8..e0f68fa 100644
--- a/avro_derive/tests/expanded/avro_rs_xxx_serde_from_into.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_xxx_serde_from_into.expanded.rs
@@ -22,31 +22,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "b".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("b".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -98,32 +111,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "b".to_string(),
-                doc: ::std::option::Option::None,
-                default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("b".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
@@ -139,15 +164,21 @@ impl ::apache_avro::AvroSchemaComponent for B {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::apache_avro::schema::Schema {
-        A::get_schema_in_ctxt(named_schemas, enclosing_namespace)
+        <A as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+            named_schemas,
+            enclosing_namespace,
+        )
     }
     fn get_record_fields_in_ctxt(
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        A::get_record_fields_in_ctxt(named_schemas, enclosing_namespace)
+        <A as ::apache_avro::AvroSchemaComponent>::get_record_fields_in_ctxt(
+            named_schemas,
+            enclosing_namespace,
+        )
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
-        A::field_default()
+        <A as ::apache_avro::AvroSchemaComponent>::field_default()
     }
 }
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs b/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
index b85a630..cc346d7 100644
--- a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
@@ -22,31 +22,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "b".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("b".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -98,32 +111,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "b".to_string(),
-                doc: ::std::option::Option::None,
-                default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("b".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
@@ -157,3 +182,29 @@ impl ::apache_avro::AvroSchemaComponent for B {
         ::std::option::Option::None
     }
 }
+#[serde(transparent)]
+struct C(A);
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for C {
+    fn get_schema_in_ctxt(
+        named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
+        enclosing_namespace: ::apache_avro::schema::NamespaceRef,
+    ) -> ::apache_avro::schema::Schema {
+        <A as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+            named_schemas,
+            enclosing_namespace,
+        )
+    }
+    fn get_record_fields_in_ctxt(
+        named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
+        enclosing_namespace: ::apache_avro::schema::NamespaceRef,
+    ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
+        <A as ::apache_avro::AvroSchemaComponent>::get_record_fields_in_ctxt(
+            named_schemas,
+            enclosing_namespace,
+        )
+    }
+    fn field_default() -> ::std::option::Option<::serde_json::Value> {
+        ::std::option::Option::None
+    }
+}
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs b/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs
index b23413b..aa0a1bc 100644
--- a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs
+++ b/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs
@@ -29,6 +29,6 @@ struct B {
     a: A,
 }
 
-// #[derive(AvroSchema)]
-// #[serde(transparent)]
-// struct C(A);
+#[derive(AvroSchema)]
+#[serde(transparent)]
+struct C(A);
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs b/avro_derive/tests/expanded/avro_rs_xxx_tag_content.expanded.rs
similarity index 55%
copy from avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
copy to avro_derive/tests/expanded/avro_rs_xxx_tag_content.expanded.rs
index b85a630..d75f321 100644
--- a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_xxx_tag_content.expanded.rs
@@ -22,31 +22,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "b".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("b".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -98,32 +111,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "b".to_string(),
-                doc: ::std::option::Option::None,
-                default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("b".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs b/avro_derive/tests/expanded/avro_rs_xxx_tag_content.rs
similarity index 100%
copy from avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs
copy to avro_derive/tests/expanded/avro_rs_xxx_tag_content.rs
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs b/avro_derive/tests/expanded/avro_rs_xxx_union_of_records.expanded.rs
similarity index 55%
copy from avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
copy to avro_derive/tests/expanded/avro_rs_xxx_union_of_records.expanded.rs
index b85a630..d75f321 100644
--- a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.expanded.rs
+++ b/avro_derive/tests/expanded/avro_rs_xxx_union_of_records.expanded.rs
@@ -22,31 +22,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
             let enclosing_namespace = name.namespace();
             named_schemas.insert(name.clone());
             {
-                let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "a".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
-                schema_fields
-                    .push(::apache_avro::schema::RecordField {
-                        name: "b".to_string(),
-                        doc: ::std::option::Option::None,
-                        default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                        aliases: ::std::vec::Vec::new(),
-                        schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                            named_schemas,
-                            enclosing_namespace,
-                        ),
-                        custom_attributes: ::std::collections::BTreeMap::new(),
-                    });
+                let schema_fields = {
+                    let mut fields = ::std::vec::Vec::with_capacity(2usize);
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("a".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                        .push(
+                            ::apache_avro::schema::RecordField::builder()
+                                .name("b".to_string())
+                                .doc(::std::option::Option::None)
+                                .maybe_default(
+                                    <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                                )
+                                .aliases(::std::vec::Vec::new())
+                                .schema(
+                                    <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                        named_schemas,
+                                        enclosing_namespace,
+                                    ),
+                                )
+                                .build(),
+                        );
+                    fields
+                };
                 let schema_field_set: ::std::collections::HashSet<_> = schema_fields
                     .iter()
                     .map(|rf| &rf.name)
@@ -98,32 +111,44 @@ impl ::apache_avro::AvroSchemaComponent for A {
         named_schemas: &mut ::std::collections::HashSet<::apache_avro::schema::Name>,
         enclosing_namespace: ::apache_avro::schema::NamespaceRef,
     ) -> ::std::option::Option<::std::vec::Vec<::apache_avro::schema::RecordField>> {
-        let mut schema_fields = Vec::with_capacity(2usize);
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "a".to_string(),
-                doc: ::std::option::Option::None,
-                default: <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        schema_fields
-            .push(::apache_avro::schema::RecordField {
-                name: "b".to_string(),
-                doc: ::std::option::Option::None,
-                default: <String as ::apache_avro::AvroSchemaComponent>::field_default(),
-                aliases: ::std::vec::Vec::new(),
-                schema: <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
-                    named_schemas,
-                    enclosing_namespace,
-                ),
-                custom_attributes: ::std::collections::BTreeMap::new(),
-            });
-        Some(schema_fields)
+        ::std::option::Option::Some({
+            let mut fields = ::std::vec::Vec::with_capacity(2usize);
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("a".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <i32 as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+                .push(
+                    ::apache_avro::schema::RecordField::builder()
+                        .name("b".to_string())
+                        .doc(::std::option::Option::None)
+                        .maybe_default(
+                            <String as ::apache_avro::AvroSchemaComponent>::field_default(),
+                        )
+                        .aliases(::std::vec::Vec::new())
+                        .schema(
+                            <String as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+                                named_schemas,
+                                enclosing_namespace,
+                            ),
+                        )
+                        .build(),
+                );
+            fields
+        })
     }
     fn field_default() -> ::std::option::Option<::serde_json::Value> {
         ::std::option::Option::None
diff --git a/avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs b/avro_derive/tests/expanded/avro_rs_xxx_union_of_records.rs
similarity index 100%
copy from avro_derive/tests/expanded/avro_rs_xxx_serde_transparent.rs
copy to avro_derive/tests/expanded/avro_rs_xxx_union_of_records.rs
diff --git a/avro_derive/tests/expanded/mod.rs b/avro_derive/tests/expanded/mod.rs
index b661b4d..80b8b23 100644
--- a/avro_derive/tests/expanded/mod.rs
+++ b/avro_derive/tests/expanded/mod.rs
@@ -29,3 +29,7 @@ mod avro_rs_501_reference;
 mod avro_rs_501_struct_with_optional;
 mod avro_rs_xxx_serde_from_into;
 mod avro_rs_xxx_serde_transparent;
+// mod avro_rs_xxx_bare_union;
+mod avro_rs_xxx_internally_tagged;
+mod avro_rs_xxx_tag_content;
+mod avro_rs_xxx_union_of_records;
diff --git a/avro_derive/tests/ui/avro_rs_501_non_basic_enum.stderr b/avro_derive/tests/ui/avro_rs_501_non_basic_enum.stderr
deleted file mode 100644
index 0099f59..0000000
--- a/avro_derive/tests/ui/avro_rs_501_non_basic_enum.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: expected expression, found `let` statement
-  --> tests/ui/avro_rs_501_non_basic_enum.rs:20:10
-   |
-20 | #[derive(AvroSchema)]
-   |          ^^^^^^^^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-   = note: this error originates in the derive macro `AvroSchema` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
-  --> tests/ui/avro_rs_501_non_basic_enum.rs:20:10
-   |
-20 | #[derive(AvroSchema)]
-   |          ^^^^^^^^^^ expected one of `)`, `,`, `.`, `?`, or an operator
-   |
-   = note: this error originates in the derive macro `AvroSchema` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: expected one of `)`, `,`, `.`, `?`, `else`, or an operator, found `::`
-  --> tests/ui/avro_rs_501_non_basic_enum.rs:20:10
-   |
-20 | #[derive(AvroSchema)]
-   |          ^^^^^^^^^^ expected one of `)`, `,`, `.`, `?`, `else`, or an operator
-   |
-   = note: this error originates in the derive macro `AvroSchema` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: proc-macro derive produced unparsable tokens
-  --> tests/ui/avro_rs_501_non_basic_enum.rs:20:10
-   |
-20 | #[derive(AvroSchema)]
-   |          ^^^^^^^^^^
-
-error[E0061]: this method takes 1 argument but 3 arguments were supplied
-  --> tests/ui/avro_rs_501_non_basic_enum.rs:20:10
-   |
-20 | #[derive(AvroSchema)]
-   |          ^^^^^^^^^^
-   |          |
-   |          unexpected argument #2 of type `()`
-   |          unexpected argument #3 of type `Schema`
-   |
-note: method defined here
-  --> $WORKSPACE/avro/src/schema/union.rs
-   |
-   |     pub fn variant(&mut self, schema: Schema) -> Result<&mut Self, Error> {
-   |            ^^^^^^^
-   = note: this error originates in the derive macro `AvroSchema` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/avro_derive/tests/ui/avro_rs_501_tuple_struct.rs b/avro_derive/tests/ui/avro_rs_501_tuple_struct.rs
deleted file mode 100644
index 1e64845..0000000
--- a/avro_derive/tests/ui/avro_rs_501_tuple_struct.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-use apache_avro::AvroSchema;
-
-#[derive(AvroSchema)]
-struct B(i32, String);
-
-fn main() {}
diff --git a/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr b/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr
deleted file mode 100644
index 1091ec0..0000000
--- a/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr
+++ /dev/null
@@ -1,5 +0,0 @@
-error: AvroSchema derive does not work for tuple structs
-  --> tests/ui/avro_rs_501_tuple_struct.rs:21:8
-   |
-21 | struct B(i32, String);
-   |        ^
diff --git a/avro_derive/tests/ui/avro_rs_501_unit_struct.stderr b/avro_derive/tests/ui/avro_rs_501_unit_struct.stderr
deleted file mode 100644
index 2a16ef6..0000000
--- a/avro_derive/tests/ui/avro_rs_501_unit_struct.stderr
+++ /dev/null
@@ -1,5 +0,0 @@
-error: AvroSchema derive does not work for unit structs
-  --> tests/ui/avro_rs_501_unit_struct.rs:21:8
-   |
-21 | struct AbsoluteUnit;
-   |        ^^^^^^^^^^^^
diff --git a/avro_derive/tests/ui/avro_rs_501_non_basic_enum.rs b/avro_derive/tests/ui/avro_rs_xxx_bare_union_and_untagged.rs
similarity index 78%
rename from avro_derive/tests/ui/avro_rs_501_non_basic_enum.rs
rename to avro_derive/tests/ui/avro_rs_xxx_bare_union_and_untagged.rs
index 72230d8..d209315 100644
--- a/avro_derive/tests/ui/avro_rs_501_non_basic_enum.rs
+++ b/avro_derive/tests/ui/avro_rs_xxx_bare_union_and_untagged.rs
@@ -18,11 +18,24 @@
 use apache_avro::AvroSchema;
 
 #[derive(AvroSchema)]
-enum NonBasic {
-    A(i32),
+#[avro(repr = "bare_union")]
+enum A {
+    A
+}
+
+#[derive(AvroSchema)]
+#[avro(repr = "bare_union")]
+#[serde(untagged)]
+enum B {
+    A,
     B,
-    C,
-    D
 }
 
-fn main() {}
+#[derive(AvroSchema)]
+#[avro(repr = "bare_union")]
+#[serde(untagged)]
+enum C {
+    A(),
+}
+
+pub fn main() {}
diff --git a/avro_derive/tests/ui/avro_rs_xxx_bare_union_and_untagged.stderr b/avro_derive/tests/ui/avro_rs_xxx_bare_union_and_untagged.stderr
new file mode 100644
index 0000000..dbe041a
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_xxx_bare_union_and_untagged.stderr
@@ -0,0 +1,20 @@
+error: AvroSchema: `#[avro(repr = "bare_union")]` requires `#[serde(untagged)]`
+  --> tests/ui/avro_rs_xxx_bare_union_and_untagged.rs:21:1
+   |
+21 | / #[avro(repr = "bare_union")]
+22 | | enum A {
+23 | |     A
+24 | | }
+   | |_^
+
+error: More than one variant maps to Schema::Null, this is not supported for bare unions
+  --> tests/ui/avro_rs_xxx_bare_union_and_untagged.rs:29:6
+   |
+29 | enum B {
+   |      ^
+
+error: AvroSchema: Empty tuple variants are not supported for bare unions
+  --> tests/ui/avro_rs_xxx_bare_union_and_untagged.rs:38:6
+   |
+38 |     A(),
+   |      ^^
diff --git a/avro_derive/tests/ui/avro_rs_xxx_serde_transparent_enum.stderr b/avro_derive/tests/ui/avro_rs_xxx_serde_transparent_enum.stderr
new file mode 100644
index 0000000..bad93cc
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_xxx_serde_transparent_enum.stderr
@@ -0,0 +1,8 @@
+error: AvroSchema: `#[serde(transparent)]` is only supported on structs
+  --> tests/ui/avro_rs_xxx_serde_transparent_enum.rs:21:1
+   |
+21 | / #[serde(transparent)]
+22 | | enum D {
+23 | |     A(A)
+24 | | }
+   | |_^