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


The following commit(s) were added to refs/heads/feat/enums by this push:
     new bd2c7c9  make type_to_* private
bd2c7c9 is described below

commit bd2c7c9e2959b7e093c5cca2e6ee288843c4cb90
Author: Kriskras99 <[email protected]>
AuthorDate: Wed Mar 11 10:06:46 2026 +0100

    make type_to_* private
---
 avro_derive/src/attributes/mod.rs                 |  27 +-
 avro_derive/src/enums/bare_union.rs               |   7 +-
 avro_derive/src/enums/record_internally_tagged.rs |   7 +-
 avro_derive/src/enums/record_tag_content.rs       |   9 +-
 avro_derive/src/fields.rs                         | 390 ++++++++++++++++++++++
 avro_derive/src/lib.rs                            | 177 +---------
 avro_derive/src/tuple.rs                          | 148 ++------
 7 files changed, 437 insertions(+), 328 deletions(-)

diff --git a/avro_derive/src/attributes/mod.rs 
b/avro_derive/src/attributes/mod.rs
index 13fadfe..ab66911 100644
--- a/avro_derive/src/attributes/mod.rs
+++ b/avro_derive/src/attributes/mod.rs
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::{case::RenameRule, type_to_field_default_expr};
+use crate::case::RenameRule;
 use darling::{FromAttributes, FromMeta};
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
@@ -389,31 +389,6 @@ 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! { ::std::option::Option::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! {
-                    
::std::option::Option::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 c465fb2..7752b81 100644
--- a/avro_derive/src/enums/bare_union.rs
+++ b/avro_derive/src/enums/bare_union.rs
@@ -1,6 +1,6 @@
-use crate::attributes::{NamedTypeOptions, VariantOptions};
+use crate::attributes::{FieldOptions, NamedTypeOptions, VariantOptions};
 use crate::tuple::tuple_struct_variant_to_record_schema;
-use crate::{named_to_record_fields, type_to_schema_expr};
+use crate::{fields, named_to_record_fields};
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
 use syn::spanned::Spanned;
@@ -47,7 +47,8 @@ pub fn get_data_enum_schema_def(
                     )]);
                 } else 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)?;
+                    let field_attrs = FieldOptions::new(&only_one.attrs, 
only_one.span())?;
+                    let schema_expr = fields::to_schema(&only_one, 
field_attrs.with)?;
                     variant_expr.push(schema_expr);
                 } else if unnamed.unnamed.len() > 1 {
                     let schema_expr = 
tuple_struct_variant_to_record_schema(unnamed, &name, &[])?;
diff --git a/avro_derive/src/enums/record_internally_tagged.rs 
b/avro_derive/src/enums/record_internally_tagged.rs
index 7d09b0d..e9173cd 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, named_to_record_fields, preserve_optional, 
type_to_schema_expr};
+use crate::attributes::{FieldOptions, NamedTypeOptions, VariantOptions};
+use crate::{aliases, fields, named_to_record_fields, preserve_optional};
 use proc_macro2::TokenStream;
 use quote::quote;
 use syn::spanned::Spanned;
@@ -36,7 +36,8 @@ pub fn get_data_enum_schema_def(
             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)?;
+                    let field_attrs = FieldOptions::new(&only_one.attrs, 
only_one.span())?;
+                    let schema_expr = fields::to_schema(&only_one, 
field_attrs.with)?;
                     field_additions.push(quote! {
                         fields.push(#schema_expr);
                     });
diff --git a/avro_derive/src/enums/record_tag_content.rs 
b/avro_derive/src/enums/record_tag_content.rs
index e39177e..a1aebf5 100644
--- a/avro_derive/src/enums/record_tag_content.rs
+++ b/avro_derive/src/enums/record_tag_content.rs
@@ -1,6 +1,6 @@
-use crate::attributes::{NamedTypeOptions, VariantOptions};
+use crate::attributes::{FieldOptions, NamedTypeOptions, VariantOptions};
 use crate::tuple::tuple_struct_variant_to_record_schema;
-use crate::{aliases, named_to_record_fields, preserve_optional, 
type_to_schema_expr};
+use crate::{aliases, fields, named_to_record_fields, preserve_optional};
 use proc_macro2::TokenStream;
 use quote::quote;
 use syn::spanned::Spanned;
@@ -50,8 +50,9 @@ pub fn get_data_enum_schema_def(
                     schema_definitions.push(schema_expr);
                 } else if unnamed.unnamed.len() == 1 {
                     let only_one = unnamed.unnamed.iter().next().expect("There 
is one");
-                    let field_schema_expr = type_to_schema_expr(&only_one.ty)?;
-                    schema_definitions.push(field_schema_expr);
+                    let field_attrs = FieldOptions::new(&only_one.attrs, 
only_one.span())?;
+                    let schema_expr = fields::to_schema(&only_one, 
field_attrs.with)?;
+                    schema_definitions.push(schema_expr);
                 } else if unnamed.unnamed.len() > 1 {
                     let schema_expr = 
tuple_struct_variant_to_record_schema(unnamed, &name, &[])?;
 
diff --git a/avro_derive/src/fields.rs b/avro_derive/src/fields.rs
new file mode 100644
index 0000000..af5b3aa
--- /dev/null
+++ b/avro_derive/src/fields.rs
@@ -0,0 +1,390 @@
+use crate::attributes::{FieldDefault, With};
+use proc_macro2::TokenStream;
+use quote::{ToTokens, quote};
+use syn::spanned::Spanned;
+use syn::{Expr, ExprLit, Field, Lit, Type, TypeArray, TypeTuple};
+
+pub fn to_schema(field: &Field, with: With) -> Result<TokenStream, 
Vec<syn::Error>> {
+    match with {
+        With::Trait => Ok(type_to_schema_expr(&field.ty)?),
+        With::Serde(path) => {
+            Ok(quote! { #path::get_schema_in_ctxt(named_schemas, 
enclosing_namespace) })
+        }
+        With::Expr(Expr::Closure(closure)) => {
+            if closure.inputs.is_empty() {
+                Ok(quote! { (#closure)() })
+            } else {
+                Err(vec![syn::Error::new(
+                    field.span(),
+                    "Expected closure with 0 parameters",
+                )])
+            }
+        }
+        With::Expr(Expr::Path(path)) => Ok(quote! { #path(named_schemas, 
enclosing_namespace) }),
+        With::Expr(_expr) => Err(vec![syn::Error::new(
+            field.span(),
+            "Invalid expression, expected function or closure",
+        )]),
+    }
+}
+
+/// Call `get_record_fields_in_ctxt` for this field.
+///
+/// # `TokenStream`
+/// ## Context
+/// The token stream expects the following variables to be defined:
+/// - `named_schemas`: `&mut HashSet<Name>`
+/// - `enclosing_namespace`: `Option<&str>`
+/// ## Returns
+/// An `Expr` that resolves to an instance of `Option<Vec<RecordField>>`.
+pub fn to_record_fields(field: &Field, with: With) -> Result<TokenStream, 
Vec<syn::Error>> {
+    match with {
+        With::Trait => Ok(type_to_record_fields(&field.ty)?),
+        With::Serde(path) => {
+            Ok(quote! { #path::get_record_fields_in_ctxt(named_schemas, 
enclosing_namespace) })
+        }
+        With::Expr(Expr::Closure(closure)) => {
+            if closure.inputs.is_empty() {
+                Ok(quote! {
+                    ::apache_avro::serde::get_record_fields_in_ctxt(
+                        named_schemas,
+                        enclosing_namespace,
+                        |_, _| (#closure)(),
+                    )
+                })
+            } else {
+                Err(vec![syn::Error::new(
+                    field.span(),
+                    "Expected closure with 0 parameters",
+                )])
+            }
+        }
+        With::Expr(Expr::Path(path)) => Ok(quote! {
+            ::apache_avro::serde::get_record_fields_in_ctxt(named_schemas, 
enclosing_namespace, #path)
+        }),
+        With::Expr(_expr) => Err(vec![syn::Error::new(
+            field.span(),
+            "Invalid expression, expected function or closure",
+        )]),
+    }
+}
+
+pub fn to_default(field: &Field, default: FieldDefault) -> Result<TokenStream, 
Vec<syn::Error>> {
+    match default {
+        FieldDefault::Disabled => Ok(quote! { ::std::option::Option::None }),
+        FieldDefault::Trait => type_to_field_default(&field.ty),
+        FieldDefault::Value(default_value) => {
+            let _: serde_json::Value = 
serde_json::from_str(&default_value[..]).map_err(|e| {
+                vec![syn::Error::new(
+                    field.span(),
+                    format!("Invalid avro default json: \n{e}"),
+                )]
+            })?;
+            Ok(quote! {
+                
::std::option::Option::Some(::serde_json::from_str(#default_value).expect("Unreachable!
 Checked at compile time"))
+            })
+        }
+    }
+}
+
+/// Takes in the Tokens of a type and returns the tokens of an expression with 
return type `Schema`
+///
+/// # `TokenStream`
+/// ## Context
+/// The token stream expects the following variables to be defined:
+/// - `named_schemas`: `&mut HashSet<Name>`
+/// - `enclosing_namespace`: `Option<&str>`
+/// ## Returns
+/// An `Expr` that resolves to an instance of `Schema`.
+fn type_to_schema_expr(ty: &Type) -> Result<TokenStream, Vec<syn::Error>> {
+    match ty {
+        Type::Slice(_) | Type::Path(_) | Type::Reference(_) => Ok(
+            quote! {<#ty as :: 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)},
+        ),
+        Type::Tuple(tuple) => tuple_to_schema(tuple),
+        Type::Array(array) => array_to_schema(array),
+        Type::Ptr(_) => Err(vec![syn::Error::new_spanned(
+            ty,
+            "AvroSchema: derive does not support raw pointers",
+        )]),
+        _ => Err(vec![syn::Error::new_spanned(
+            ty,
+            format!(
+                "AvroSchema: Unexpected type encountered! Please open an issue 
if this kind of type should be supported: {ty:?}"
+            ),
+        )]),
+    }
+}
+
+/// Create a schema definition for a tuple.
+///
+/// # Mapping
+/// - `0-tuple` => `Schema::Null`,
+/// - `1-tuple` => Schema of the only element,
+/// - `n-tuple` => `Schema::Record`.
+///
+/// # `TokenStream`
+/// ## Context
+/// The token stream expects the following variables to be defined:
+/// - `named_schemas`: `&mut HashSet<Name>`
+/// - `enclosing_namespace`: `Option<&str>`
+/// ## Returns
+/// An `Expr` that resolves to an instance of `Schema`.
+fn tuple_to_schema(tuple: &TypeTuple) -> Result<TokenStream, Vec<syn::Error>> {
+    if tuple.elems.is_empty() {
+        Ok(quote! {::apache_avro::schema::Schema::Null})
+    } else if tuple.elems.len() == 1 {
+        type_to_schema_expr(&tuple.elems.iter().next().unwrap())
+    } else {
+        let mut fields = Vec::with_capacity(tuple.elems.len());
+
+        for (index, elem) in tuple.elems.iter().enumerate() {
+            let name = format!("field_{index}");
+            let field_schema_expr = type_to_schema_expr(elem)?;
+            fields.push(quote! {
+                ::apache_avro::schema::RecordField::builder()
+                    .name(#name.to_string())
+                    .schema(#field_schema_expr)
+                    .build()
+            });
+        }
+
+        // Try to create a unique name for this record, this is done in a best 
effort way and the
+        // name is NOT recorded in `names`.
+        // This will always start and end with a `_` as `(` and `)` are not 
valid characters
+        let tuple_as_valid_name = tuple
+            .to_token_stream()
+            .to_string()
+            .chars()
+            .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
+            .collect::<String>();
+
+        let name = format!("tuple_{}{tuple_as_valid_name}", tuple.elems.len());
+
+        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(vec![
+                    #(#fields, )*
+                ])
+                .attributes(
+                    [
+                        ("org.apache.avro.rust.tuple".to_string(), 
::serde_json::value::Value::Bool(true)),
+                    ].into()
+                )
+                .build()
+            )
+        })
+    }
+}
+
+/// Create a schema definition for an array.
+///
+/// # Mapping
+/// - `[T; 0]` => `Schema::Null`,
+/// - `[T; 1]` => Schema of `T`,
+/// - `[T; N]` => `Schema::Record`.
+///
+/// # `TokenStream`
+/// ## Context
+/// The token stream expects the following variables to be defined:
+/// - `named_schemas`: `&mut HashSet<Name>`
+/// - `enclosing_namespace`: `Option<&str>`
+/// ## Returns
+/// An `Expr` that resolves to an instance of `Schema`.
+fn array_to_schema(array: &TypeArray) -> Result<TokenStream, Vec<syn::Error>> {
+    let Expr::Lit(ExprLit {
+        lit: Lit::Int(lit), ..
+    }) = &array.len
+    else {
+        return Err(vec![syn::Error::new(
+            array.span(),
+            "AvroSchema: Expected a integer literal for the array length",
+        )]);
+    };
+    // This should always work as the length always needs to fit in a usize
+    let len: usize = lit.base10_parse().map_err(|e| vec![e])?;
+
+    if len == 0 {
+        Ok(quote! {::apache_avro::schema::Schema::Null})
+    } else if len == 1 {
+        type_to_schema_expr(&array.elem)
+    } else {
+        let t_schema_expr = type_to_schema_expr(&array.elem)?;
+        let fields = (0..len).map(|index| {
+            let name = format!("field_{index}");
+            quote! {
+                ::apache_avro::schema::RecordField::builder()
+                    .name(#name.to_string())
+                    .schema(#t_schema_expr)
+                    .build()
+            }
+        });
+
+        // Try to create a unique name for this record, this is done as best 
effort and the
+        // name is NOT recorded in `names`.
+        let array_elem_as_valid_name = array
+            .elem
+            .to_token_stream()
+            .to_string()
+            .chars()
+            .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
+            .collect::<String>();
+
+        let name = format!("array_{len}_{array_elem_as_valid_name}");
+
+        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(vec![
+                    #(#fields, )*
+                ])
+                .attributes(
+                    [
+                        ("org.apache.avro.rust.tuple".to_string(), 
::serde_json::value::Value::Bool(true)),
+                    ].into()
+                )
+                .build()
+            )
+        })
+    }
+}
+
+fn type_to_record_fields(ty: &Type) -> Result<TokenStream, Vec<syn::Error>> {
+    match ty {
+        Type::Slice(_) | Type::Path(_) | Type::Reference(_) => Ok(
+            quote! {<#ty as :: 
apache_avro::AvroSchemaComponent>::get_record_fields_in_ctxt(named_schemas, 
enclosing_namespace)},
+        ),
+        Type::Array(array) => array_to_record_fields(array),
+        Type::Tuple(tuple) => tuple_to_record_fields(tuple),
+        Type::Ptr(_) => Err(vec![syn::Error::new_spanned(
+            ty,
+            "AvroSchema: derive does not support raw pointers",
+        )]),
+        _ => Err(vec![syn::Error::new_spanned(
+            ty,
+            format!(
+                "AvroSchema: Unexpected type encountered! Please open an issue 
if this kind of type should be supported: {ty:?}"
+            ),
+        )]),
+    }
+}
+
+/// Create a schema definition for a tuple.
+///
+/// # Mapping
+/// - `0-tuple` => `Schema::Null`,
+/// - `1-tuple` => Schema of the only element,
+/// - `n-tuple` => `Schema::Record`.
+///
+/// # `TokenStream`
+/// ## Context
+/// The token stream expects the following variables to be defined:
+/// - `named_schemas`: `&mut HashSet<Name>`
+/// - `enclosing_namespace`: `Option<&str>`
+/// ## Returns
+/// An `Expr` that resolves to an instance of `Schema`.
+fn tuple_to_record_fields(tuple: &TypeTuple) -> Result<TokenStream, 
Vec<syn::Error>> {
+    if tuple.elems.is_empty() {
+        Ok(quote! {::std::option::Option::None})
+    } else if tuple.elems.len() == 1 {
+        type_to_record_fields(&tuple.elems.iter().next().unwrap())
+    } else {
+        let mut fields = Vec::with_capacity(tuple.elems.len());
+
+        for (index, elem) in tuple.elems.iter().enumerate() {
+            let name = format!("field_{index}");
+            let field_schema_expr = type_to_schema_expr(elem)?;
+            fields.push(quote! {
+                ::apache_avro::schema::RecordField::builder()
+                    .name(#name.to_string())
+                    .schema(#field_schema_expr)
+                    .build()
+            });
+        }
+
+        Ok(quote! {
+            ::std::option::Option::Some(vec![#(#fields, )*])
+        })
+    }
+}
+/// Create a schema definition for an array.
+///
+/// # Mapping
+/// - `[T; 0]` => `Schema::Null`,
+/// - `[T; 1]` => Schema of `T`,
+/// - `[T; N]` => `Schema::Record`.
+///
+/// # `TokenStream`
+/// ## Context
+/// The token stream expects the following variables to be defined:
+/// - `named_schemas`: `&mut HashSet<Name>`
+/// - `enclosing_namespace`: `Option<&str>`
+/// ## Returns
+/// An `Expr` that resolves to an instance of `Schema`.
+fn array_to_record_fields(array: &TypeArray) -> Result<TokenStream, 
Vec<syn::Error>> {
+    let Expr::Lit(ExprLit {
+                      lit: Lit::Int(lit), ..
+                  }) = &array.len
+    else {
+        return Err(vec![syn::Error::new(
+            array.span(),
+            "AvroSchema: Expected a integer literal for the array length",
+        )]);
+    };
+    // This should always work as the length always needs to fit in a usize
+    let len: usize = lit.base10_parse().map_err(|e| vec![e])?;
+
+    if len == 0 {
+        Ok(quote! {::std::option::Option::None})
+    } else if len == 1 {
+        type_to_record_fields(&array.elem)
+    } else {
+        let t_schema_expr = type_to_schema_expr(&array.elem)?;
+        let fields = (0..len).map(|index| {
+            let name = format!("field_{index}");
+            quote! {
+                ::apache_avro::schema::RecordField::builder()
+                    .name(#name.to_string())
+                    .schema(#t_schema_expr)
+                    .build()
+            }
+        });
+
+        Ok(quote! {
+            ::std::option::Option::Some(vec![#(#fields, )*])
+        })
+    }
+}
+
+fn type_to_field_default(ty: &Type) -> Result<TokenStream, Vec<syn::Error>> {
+    match ty {
+        Type::Slice(_) | Type::Path(_) | Type::Reference(_) => {
+            Ok(quote! {<#ty as :: 
apache_avro::AvroSchemaComponent>::field_default()})
+        }
+        Type::Ptr(_) => Err(vec![syn::Error::new_spanned(
+            ty,
+            "AvroSchema: derive does not support raw pointers",
+        )]),
+        Type::Tuple(_) | Type::Array(_) => Ok(quote! { 
::std::option::Option::None }),
+        _ => Err(vec![syn::Error::new_spanned(
+            ty,
+            format!(
+                "AvroSchema: Unexpected type encountered! Please open an issue 
if this kind of type should be supported: {ty:?}"
+            ),
+        )]),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use pretty_assertions::assert_eq;
+
+    #[test]
+    fn test_trait_cast() {
+        
assert_eq!(type_to_schema_expr(&syn::parse2::<Type>(quote!{i32}).unwrap()).unwrap().to_string(),
 quote!{<i32 as :: 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
+        
assert_eq!(type_to_schema_expr(&syn::parse2::<Type>(quote!{Vec<T>}).unwrap()).unwrap().to_string(),
 quote!{<Vec<T> as :: 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
+        
assert_eq!(type_to_schema_expr(&syn::parse2::<Type>(quote!{AnyType}).unwrap()).unwrap().to_string(),
 quote!{<AnyType as :: 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
+    }
+}
diff --git a/avro_derive/src/lib.rs b/avro_derive/src/lib.rs
index 84daff0..ab3e8c2 100644
--- a/avro_derive/src/lib.rs
+++ b/avro_derive/src/lib.rs
@@ -32,18 +32,18 @@
 mod attributes;
 mod case;
 mod enums;
+mod fields;
 mod tuple;
 
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
 use syn::{
-    DataStruct, DeriveInput, Expr, Field, Fields, FieldsNamed, Generics, 
Ident, Type,
-    parse_macro_input, spanned::Spanned,
+    DataStruct, DeriveInput, Fields, FieldsNamed, Generics, Ident, Type, 
parse_macro_input,
+    spanned::Spanned,
 };
 
-use crate::tuple::tuple_to_schema;
 use crate::{
-    attributes::{FieldOptions, NamedTypeOptions, With},
+    attributes::{FieldOptions, NamedTypeOptions},
     case::RenameRule,
     tuple::unnamed_to_record_fields,
 };
@@ -235,8 +235,8 @@ fn get_transparent_struct_schema_def(
 
             if let Some((field, attrs)) = found {
                 Ok((
-                    get_field_schema_expr(&field, attrs.with.clone())?,
-                    get_field_get_record_fields_expr(&field, attrs.with)?,
+                    fields::to_schema(&field, attrs.with.clone())?,
+                    fields::to_record_fields(&field, attrs.with)?,
                 ))
             } else {
                 Err(vec![syn::Error::new(
@@ -262,8 +262,8 @@ fn get_transparent_struct_schema_def(
 
             if let Some((field, attrs)) = found {
                 Ok((
-                    get_field_schema_expr(&field, attrs.with.clone())?,
-                    get_field_get_record_fields_expr(&field, attrs.with)?,
+                    fields::to_schema(&field, attrs.with.clone())?,
+                    fields::to_record_fields(&field, attrs.with)?,
                 ))
             } else {
                 Err(vec![syn::Error::new(
@@ -279,146 +279,6 @@ fn get_transparent_struct_schema_def(
     }
 }
 
-fn get_field_schema_expr(field: &Field, with: With) -> Result<TokenStream, 
Vec<syn::Error>> {
-    match with {
-        With::Trait => Ok(type_to_schema_expr(&field.ty)?),
-        With::Serde(path) => {
-            Ok(quote! { #path::get_schema_in_ctxt(named_schemas, 
enclosing_namespace) })
-        }
-        With::Expr(Expr::Closure(closure)) => {
-            if closure.inputs.is_empty() {
-                Ok(quote! { (#closure)() })
-            } else {
-                Err(vec![syn::Error::new(
-                    field.span(),
-                    "Expected closure with 0 parameters",
-                )])
-            }
-        }
-        With::Expr(Expr::Path(path)) => Ok(quote! { #path(named_schemas, 
enclosing_namespace) }),
-        With::Expr(_expr) => Err(vec![syn::Error::new(
-            field.span(),
-            "Invalid expression, expected function or closure",
-        )]),
-    }
-}
-
-/// Call `get_record_fields_in_ctxt` for this field.
-///
-/// # `TokenStream`
-/// ## Context
-/// The token stream expects the following variables to be defined:
-/// - `named_schemas`: `&mut HashSet<Name>`
-/// - `enclosing_namespace`: `Option<&str>`
-/// ## Returns
-/// A call to a `get_record_fields_in_ctxt(named_schemas, enclosing_namespace) 
-> Option<Vec<RecordField>>`
-fn get_field_get_record_fields_expr(
-    field: &Field,
-    with: With,
-) -> Result<TokenStream, Vec<syn::Error>> {
-    match with {
-        With::Trait => Ok(type_to_get_record_fields_expr(&field.ty)?),
-        With::Serde(path) => {
-            Ok(quote! { #path::get_record_fields_in_ctxt(named_schemas, 
enclosing_namespace) })
-        }
-        With::Expr(Expr::Closure(closure)) => {
-            if closure.inputs.is_empty() {
-                Ok(quote! {
-                    ::apache_avro::serde::get_record_fields_in_ctxt(
-                        named_schemas,
-                        enclosing_namespace,
-                        |_, _| (#closure)(),
-                    )
-                })
-            } else {
-                Err(vec![syn::Error::new(
-                    field.span(),
-                    "Expected closure with 0 parameters",
-                )])
-            }
-        }
-        With::Expr(Expr::Path(path)) => Ok(quote! {
-            ::apache_avro::serde::get_record_fields_in_ctxt(named_schemas, 
enclosing_namespace, #path)
-        }),
-        With::Expr(_expr) => Err(vec![syn::Error::new(
-            field.span(),
-            "Invalid expression, expected function or closure",
-        )]),
-    }
-}
-
-/// Takes in the Tokens of a type and returns the tokens of an expression with 
return type `Schema`
-///
-/// # `TokenStream`
-/// ## Context
-/// The token stream expects the following variables to be defined:
-/// - `named_schemas`: `&mut HashSet<Name>`
-/// - `enclosing_namespace`: `Option<&str>`
-/// ## Returns
-/// A call to a `get_schema_in_ctxt(named_schemas, enclosing_namespace) -> 
Schema`
-fn type_to_schema_expr(ty: &Type) -> Result<TokenStream, Vec<syn::Error>> {
-    match ty {
-        Type::Array(_) | Type::Slice(_) | Type::Path(_) | Type::Reference(_) 
=> Ok(
-            quote! {<#ty as :: 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)},
-        ),
-        Type::Ptr(_) => Err(vec![syn::Error::new_spanned(
-            ty,
-            "AvroSchema: derive does not support raw pointers",
-        )]),
-        Type::Tuple(tuple) => tuple_to_schema(tuple),
-        _ => Err(vec![syn::Error::new_spanned(
-            ty,
-            format!(
-                "AvroSchema: Unexpected type encountered! Please open an issue 
if this kind of type should be supported: {ty:?}"
-            ),
-        )]),
-    }
-}
-
-fn type_to_get_record_fields_expr(ty: &Type) -> Result<TokenStream, 
Vec<syn::Error>> {
-    match ty {
-        Type::Array(_) | Type::Slice(_) | Type::Path(_) | Type::Reference(_) 
=> Ok(
-            quote! {<#ty as :: 
apache_avro::AvroSchemaComponent>::get_record_fields_in_ctxt(named_schemas, 
enclosing_namespace)},
-        ),
-        Type::Ptr(_) => Err(vec![syn::Error::new_spanned(
-            ty,
-            "AvroSchema: derive does not support raw pointers",
-        )]),
-        Type::Tuple(_) => Err(vec![syn::Error::new_spanned(
-            ty,
-            "AvroSchema: derive does not support tuples",
-        )]),
-        _ => Err(vec![syn::Error::new_spanned(
-            ty,
-            format!(
-                "AvroSchema: Unexpected type encountered! Please open an issue 
if this kind of type should be supported: {ty:?}"
-            ),
-        )]),
-    }
-}
-
-fn type_to_field_default_expr(ty: &Type) -> Result<TokenStream, 
Vec<syn::Error>> {
-    match ty {
-        Type::Array(_) | Type::Slice(_) | Type::Path(_) | Type::Reference(_) 
=> {
-            Ok(quote! {<#ty as :: 
apache_avro::AvroSchemaComponent>::field_default()})
-        }
-        Type::Ptr(_) => Err(vec![syn::Error::new_spanned(
-            ty,
-            "AvroSchema: derive does not support raw pointers",
-        )]),
-        Type::Tuple(_) => Err(vec![syn::Error::new_spanned(
-            ty,
-            "AvroSchema: derive does not support tuples",
-        )]),
-        _ => Err(vec![syn::Error::new_spanned(
-            ty,
-            format!(
-                "AvroSchema: Unexpected type encountered! Please open an issue 
if this kind of type should be supported: {ty:?}"
-            ),
-        )]),
-    }
-}
-
 /// Create a vector of `RecordField`s.
 fn named_to_record_fields(
     named: FieldsNamed,
@@ -432,7 +292,7 @@ fn named_to_record_fields(
         } 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)?;
+            let get_record_fields = fields::to_record_fields(&field, 
field_attrs.with)?;
             fields.push(quote! {
                 if let Some(flattened_fields) = #get_record_fields {
                     fields.extend(flattened_fields);
@@ -461,12 +321,10 @@ fn named_to_record_fields(
             }
             _ => {}
         }
-        let default_value = field_attrs
-            .default
-            .into_tokenstream(field.ident.span(), &field.ty)?;
+        let default_value = fields::to_default(&field, field_attrs.default)?;
         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)?;
+        let field_schema_expr = fields::to_schema(&field, field_attrs.with)?;
         fields.push(quote! {
             fields.push(::apache_avro::schema::RecordField::builder()
                 .name(#name.to_string())
@@ -534,16 +392,3 @@ fn field_aliases(op: &[impl quote::ToTokens]) -> 
TokenStream {
         quote! {vec![#(#items),*]}
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use pretty_assertions::assert_eq;
-
-    #[test]
-    fn test_trait_cast() {
-        
assert_eq!(type_to_schema_expr(&syn::parse2::<Type>(quote!{i32}).unwrap()).unwrap().to_string(),
 quote!{<i32 as :: 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
-        
assert_eq!(type_to_schema_expr(&syn::parse2::<Type>(quote!{Vec<T>}).unwrap()).unwrap().to_string(),
 quote!{<Vec<T> as :: 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
-        
assert_eq!(type_to_schema_expr(&syn::parse2::<Type>(quote!{AnyType}).unwrap()).unwrap().to_string(),
 quote!{<AnyType as :: 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
-    }
-}
diff --git a/avro_derive/src/tuple.rs b/avro_derive/src/tuple.rs
index adf56c4..8253332 100644
--- a/avro_derive/src/tuple.rs
+++ b/avro_derive/src/tuple.rs
@@ -1,15 +1,23 @@
 use proc_macro2::TokenStream;
-use quote::{ToTokens, quote};
-use syn::{Expr, ExprLit, FieldsUnnamed, Lit, TypeArray, TypeTuple, 
spanned::Spanned};
+use quote::quote;
+use syn::{FieldsUnnamed, spanned::Spanned};
 
-use crate::{FieldOptions, doc_into_tokenstream, field_aliases, 
type_to_schema_expr};
+use crate::{FieldOptions, doc_into_tokenstream, field_aliases, fields};
 
 /// 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`.
+/// The schema will have the attribute `org.apache.avro.rust.tuple` any other 
specified in `extra_attributes`.
 /// All attributes will have a value of `true`.
+///
+/// # `TokenStream`
+/// ## Context
+/// The token stream expects the following variables to be defined:
+/// - `named_schemas`: `&mut HashSet<Name>`
+/// - `enclosing_namespace`: `Option<&str>`
+/// ## Returns
+/// An `Expr` that resolves to an instance of `Schema`.
 pub fn tuple_struct_variant_to_record_schema(
     unnamed: FieldsUnnamed,
     name: &str,
@@ -32,125 +40,15 @@ pub fn tuple_struct_variant_to_record_schema(
     })
 }
 
-/// Create a schema definition for a tuple.
-///
-/// # Mapping
-/// - `0-tuple` => `Schema::Null`,
-/// - `1-tuple` => Schema of the only element,
-/// - `n-tuple` => `Schema::Record`.
-pub fn tuple_to_schema(tuple: &TypeTuple) -> Result<TokenStream, 
Vec<syn::Error>> {
-    if tuple.elems.is_empty() {
-        Ok(quote! {::apache_avro::schema::Schema::Null})
-    } else if tuple.elems.len() == 1 {
-        type_to_schema_expr(&tuple.elems.iter().next().unwrap())
-    } else {
-        let mut fields = Vec::with_capacity(tuple.elems.len());
-
-        for (index, elem) in tuple.elems.iter().enumerate() {
-            let name = format!("field_{index}");
-            let field_schema_expr = type_to_schema_expr(elem)?;
-            fields.push(quote! {
-                ::apache_avro::schema::RecordField::builder()
-                    .name(#name.to_string())
-                    .schema(#field_schema_expr)
-                    .build()
-            });
-        }
-
-        // Try to create a unique name for this record, this is done in a best 
effort way and the
-        // name is NOT recorded in `names`.
-        // This will always start and end with a `_` as `(` and `)` are not 
valid characters
-        let tuple_as_valid_name = tuple
-            .to_token_stream()
-            .to_string()
-            .chars()
-            .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
-            .collect::<String>();
-
-        let name = format!("tuple_{}{tuple_as_valid_name}", tuple.elems.len());
-
-        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(vec![
-                    #(#fields, )*
-                ])
-                .attributes(
-                    [
-                        ("org.apache.avro.rust.tuple".to_string(), 
::serde_json::value::Value::Bool(true)),
-                    ].into()
-                )
-                .build()
-            )
-        })
-    }
-}
-
-/// Create a schema definition for an array.
-///
-/// # Mapping
-/// - `[T; 0]` => `Schema::Null`,
-/// - `[T; 1]` => Schema of `T`,
-/// - `[T; N]` => `Schema::Record`.
-pub fn array_to_schema(array: &TypeArray) -> Result<TokenStream, 
Vec<syn::Error>> {
-    let Expr::Lit(ExprLit {
-        lit: Lit::Int(lit), ..
-    }) = &array.len
-    else {
-        return Err(vec![syn::Error::new(
-            array.span(),
-            "AvroSchema: Expected a integer literal for the array length",
-        )]);
-    };
-    // This should always work as the length always needs to fit in a usize
-    let len: usize = lit.base10_parse().map_err(|e| vec![e])?;
-
-    if len == 0 {
-        Ok(quote! {::apache_avro::schema::Schema::Null})
-    } else if len == 1 {
-        type_to_schema_expr(&array.elem)
-    } else {
-        let t_schema_expr = type_to_schema_expr(&array.elem)?;
-        let fields = (0..len).map(|index| {
-            let name = format!("field_{index}");
-            quote! {
-                ::apache_avro::schema::RecordField::builder()
-                    .name(#name.to_string())
-                    .schema(#t_schema_expr)
-                    .build()
-            }
-        });
-
-        // Try to create a unique name for this record, this is done as best 
effort and the
-        // name is NOT recorded in `names`.
-        let array_elem_as_valid_name = array
-            .elem
-            .to_token_stream()
-            .to_string()
-            .chars()
-            .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
-            .collect::<String>();
-
-        let name = format!("array_{len}_{array_elem_as_valid_name}");
-
-        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(vec![
-                    #(#fields, )*
-                ])
-                .attributes(
-                    [
-                        ("org.apache.avro.rust.tuple".to_string(), 
::serde_json::value::Value::Bool(true)),
-                    ].into()
-                )
-                .build()
-            )
-        })
-    }
-}
-
 /// Create a vector of `RecordField`s named `field_{field_index}`.
+///
+/// # `TokenStream`
+/// ## Context
+/// The token stream expects the following variables to be defined:
+/// - `named_schemas`: `&mut HashSet<Name>`
+/// - `enclosing_namespace`: `Option<&str>`
+/// ## Returns
+/// An `Expr` that resolves to an instance of `Vec<RecordField>`.
 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() {
@@ -163,15 +61,13 @@ pub fn unnamed_to_record_fields(unnamed: FieldsUnnamed) -> 
Result<TokenStream, V
                 "AvroSchema: `#[serde(flatten)]` is not supported on tuple 
fields",
             )]);
         }
-        let default_value = field_attrs
-            .default
-            .into_tokenstream(field.ident.span(), &field.ty)?;
+        let default_value = fields::to_default(&field, field_attrs.default)?;
         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)?;
+        let field_schema_expr = crate::fields::to_schema(&field, 
field_attrs.with)?;
         fields.push(quote! {
             ::apache_avro::schema::RecordField::builder()
                 .name(#name.to_string())


Reply via email to