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

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


The following commit(s) were added to refs/heads/main by this push:
     new ac79ec6  fix(derive): do not match type by name (#401)
ac79ec6 is described below

commit ac79ec6c49bbe287e9146b0f34aaf19462217f97
Author: Kriskras99 <[email protected]>
AuthorDate: Thu Jan 15 12:20:23 2026 +0100

    fix(derive): do not match type by name (#401)
    
    * fix(derive): do not match type by name
    
    * feat: Implement `AvroSchemaComponent` for more types and simplify the 
derive
    
    * chore: Changing naming of parameter from variants to schemas
    
    * chore: Stronger error message
    
    ---------
    
    Co-authored-by: default <[email protected]>
---
 avro/src/schema.rs                                 | 110 ++++++++++++++++++++-
 avro_derive/src/lib.rs                             |  77 +++++----------
 avro_derive/tests/derive.rs                        |  85 ++++++++++++++++
 avro_derive/tests/ui/avro_rs_401_ptr.rs            |  25 +++++
 avro_derive/tests/ui/avro_rs_401_ptr.stderr        |   5 +
 avro_derive/tests/ui/avro_rs_401_tuple.rs          |  25 +++++
 avro_derive/tests/ui/avro_rs_401_tuple.stderr      |   5 +
 .../tests/ui/avro_rs_401_unknown_type_variant.rs   |  25 +++++
 .../ui/avro_rs_401_unknown_type_variant.stderr     |   5 +
 9 files changed, 308 insertions(+), 54 deletions(-)

diff --git a/avro/src/schema.rs b/avro/src/schema.rs
index 809606a..ce75832 100644
--- a/avro/src/schema.rs
+++ b/avro/src/schema.rs
@@ -979,6 +979,10 @@ pub struct UnionSchema {
 
 impl UnionSchema {
     /// Creates a new UnionSchema from a vector of schemas.
+    ///
+    /// # Errors
+    /// Will return an error if `schemas` has duplicate unnamed schemas or if 
`schemas`
+    /// contains a union.
     pub fn new(schemas: Vec<Schema>) -> AvroResult<Self> {
         let mut vindex = BTreeMap::new();
         for (i, schema) in schemas.iter().enumerate() {
@@ -1380,6 +1384,15 @@ impl Schema {
         })
     }
 
+    /// Returns a [`Schema::Union`] with the given variants.
+    ///
+    /// # Errors
+    /// Will return an error if `schemas` has duplicate unnamed schemas or if 
`schemas`
+    /// contains a union.
+    pub fn union(schemas: Vec<Schema>) -> AvroResult<Schema> {
+        UnionSchema::new(schemas).map(Schema::Union)
+    }
+
     fn denormalize(&mut self, schemata: &[Schema]) -> AvroResult<()> {
         match self {
             Schema::Ref { name } => {
@@ -2570,6 +2583,10 @@ fn field_ordering_position(field: &str) -> Option<usize> 
{
 /// through `derive` feature. Do not implement directly!
 /// Implement [`AvroSchemaComponent`] to get this trait
 /// through a blanket implementation.
+///
+/// Note: This trait is **not** implemented for `char` and `u64`. `char` is a 
32-bit value
+/// that does not have a logical mapping to an Avro schema. `u64` is too large 
to fit in a
+/// Avro `long`.
 pub trait AvroSchema {
     fn get_schema() -> Schema;
 }
@@ -2578,6 +2595,10 @@ pub trait AvroSchema {
 /// implementation available through `derive` feature. This is what is 
implemented by
 /// the `derive(AvroSchema)` macro.
 ///
+/// Note: This trait is **not** implemented for `char` and `u64`. `char` is a 
32-bit value
+/// that does not have a logical mapping to an Avro schema. `u64` is too large 
to fit in a
+/// Avro `long`.
+///
 /// # Implementation guide
 ///
 /// ### Simple implementation
@@ -2629,7 +2650,7 @@ pub trait AvroSchemaComponent {
 
 impl<T> AvroSchema for T
 where
-    T: AvroSchemaComponent,
+    T: AvroSchemaComponent + ?Sized,
 {
     fn get_schema() -> Schema {
         T::get_schema_in_ctxt(&mut HashMap::default(), &None)
@@ -2657,8 +2678,45 @@ impl_schema!(u32, Schema::Long);
 impl_schema!(f32, Schema::Float);
 impl_schema!(f64, Schema::Double);
 impl_schema!(String, Schema::String);
+impl_schema!(str, Schema::String);
 impl_schema!(uuid::Uuid, Schema::Uuid(UuidSchema::String));
 
+impl<T> AvroSchemaComponent for &T
+where
+    T: AvroSchemaComponent + ?Sized,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
+    }
+}
+
+impl<T> AvroSchemaComponent for &mut T
+where
+    T: AvroSchemaComponent + ?Sized,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
+    }
+}
+
+impl<T> AvroSchemaComponent for [T]
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        Schema::array(T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace))
+    }
+}
+
+impl<const N: usize, T> AvroSchemaComponent for [T; N]
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        Schema::array(T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace))
+    }
+}
+
 impl<T> AvroSchemaComponent for Vec<T>
 where
     T: AvroSchemaComponent,
@@ -7590,4 +7648,54 @@ mod tests {
 
         Ok(())
     }
+
+    #[test]
+    fn avro_rs_401_str() -> TestResult {
+        let schema = str::get_schema();
+        assert_eq!(schema, Schema::String);
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_401_references() -> TestResult {
+        let schema_ref = <&str>::get_schema();
+        let schema_ref_mut = <&mut str>::get_schema();
+
+        assert_eq!(schema_ref, Schema::String);
+        assert_eq!(schema_ref_mut, Schema::String);
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_401_slice() -> TestResult {
+        let schema = <[u8]>::get_schema();
+        assert_eq!(schema, Schema::array(Schema::Int));
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_401_array() -> TestResult {
+        let schema = <[u8; 55]>::get_schema();
+        assert_eq!(schema, Schema::array(Schema::Int));
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_401_option_ref_slice_array() -> TestResult {
+        let schema = <Option<&[[u8; 55]]>>::get_schema();
+        assert_eq!(
+            schema,
+            Schema::union(vec![
+                Schema::Null,
+                Schema::array(Schema::array(Schema::Int))
+            ])
+            .unwrap()
+        );
+
+        Ok(())
+    }
 }
diff --git a/avro_derive/src/lib.rs b/avro_derive/src/lib.rs
index c3587ed..9d9490f 100644
--- a/avro_derive/src/lib.rs
+++ b/avro_derive/src/lib.rs
@@ -23,8 +23,7 @@ mod case;
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
 use syn::{
-    AttrStyle, Attribute, DeriveInput, Ident, Meta, Type, TypePath, 
parse_macro_input,
-    spanned::Spanned,
+    AttrStyle, Attribute, DeriveInput, Ident, Meta, Type, parse_macro_input, 
spanned::Spanned,
 };
 
 use crate::{
@@ -266,45 +265,24 @@ fn get_data_enum_schema_def(
 
 /// Takes in the Tokens of a type and returns the tokens of an expression with 
return type `Schema`
 fn type_to_schema_expr(ty: &Type) -> Result<TokenStream, Vec<syn::Error>> {
-    if let Type::Path(p) = ty {
-        let type_string = p.path.segments.last().unwrap().ident.to_string();
-
-        let schema = match &type_string[..] {
-            "bool" => quote! {apache_avro::schema::Schema::Boolean},
-            "i8" | "i16" | "i32" | "u8" | "u16" => quote! 
{apache_avro::schema::Schema::Int},
-            "u32" | "i64" => quote! {apache_avro::schema::Schema::Long},
-            "f32" => quote! {apache_avro::schema::Schema::Float},
-            "f64" => quote! {apache_avro::schema::Schema::Double},
-            "String" | "str" => quote! {apache_avro::schema::Schema::String},
-            "char" => {
-                return Err(vec![syn::Error::new_spanned(
-                    ty,
-                    "AvroSchema: Cannot guarantee successful deserialization 
of this type",
-                )]);
-            }
-            "u64" => {
-                return Err(vec![syn::Error::new_spanned(
-                    ty,
-                    "Cannot guarantee successful serialization of this type 
due to overflow concerns",
-                )]);
-            } // Can't guarantee serialization type
-            _ => {
-                // Fails when the type does not implement AvroSchemaComponent 
directly
-                // TODO check and error report with something like 
https://docs.rs/quote/1.0.15/quote/macro.quote_spanned.html#example
-                type_path_schema_expr(p)
-            }
-        };
-        Ok(schema)
-    } else if let Type::Array(ta) = ty {
-        let inner_schema_expr = type_to_schema_expr(&ta.elem)?;
-        Ok(quote! {apache_avro::schema::Schema::array(#inner_schema_expr)})
-    } else if let Type::Reference(tr) = ty {
-        type_to_schema_expr(&tr.elem)
-    } else {
-        Err(vec![syn::Error::new_spanned(
+    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,
-            format!("Unable to generate schema for type: {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:?}"
+            ),
+        )]),
     }
 }
 
@@ -337,13 +315,6 @@ fn is_default_attr(attr: &Attribute) -> bool {
     matches!(attr, Attribute { meta: Meta::Path(path), .. } if 
path.get_ident().map(Ident::to_string).as_deref() == Some("default"))
 }
 
-/// Generates the schema def expression for fully qualified type paths using 
the associated function
-/// - `A -> <A as apache_avro::AvroSchemaComponent>::get_schema_in_ctxt()`
-/// - `A<T> -> <A<T> as 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt()`
-fn type_path_schema_expr(p: &TypePath) -> TokenStream {
-    quote! {<#p as 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}
-}
-
 /// 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);
@@ -640,9 +611,9 @@ mod tests {
 
     #[test]
     fn test_trait_cast() {
-        
assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{i32}).unwrap()).to_string(),
 quote!{<i32 as 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
-        
assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{Vec<T>}).unwrap()).to_string(),
 quote!{<Vec<T> as 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
-        
assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{AnyType}).unwrap()).to_string(),
 quote!{<AnyType as 
apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}.to_string());
+        
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());
     }
 
     #[test]
@@ -658,7 +629,7 @@ mod tests {
         match syn::parse2::<DeriveInput>(test_struct) {
             Ok(mut input) => {
                 let schema_res = derive_avro_schema(&mut input);
-                let expected_token_stream = r#"let mut schema_fields = Vec :: 
with_capacity (1usize) ; schema_fields . push (:: apache_avro :: schema :: 
RecordField { name : "a3" . to_string () , doc : Some ("a doc" . into ()) , 
default : Some (serde_json :: from_str ("123") . expect (format ! ("Invalid 
JSON: {:?}" , "123") . as_str ())) , aliases : Some (vec ! ["a1" . into () , 
"a2" . into ()]) , schema : apache_avro :: schema :: Schema :: Int , order : :: 
apache_avro :: schema :: Recor [...]
+                let expected_token_stream = r#"let mut schema_fields = Vec :: 
with_capacity (1usize) ; schema_fields . push (:: apache_avro :: schema :: 
RecordField { name : "a3" . to_string () , doc : Some ("a doc" . into ()) , 
default : Some (serde_json :: from_str ("123") . expect (format ! ("Invalid 
JSON: {:?}" , "123") . as_str ())) , aliases : Some (vec ! ["a1" . into () , 
"a2" . into ()]) , schema : < i32 as apache_avro :: AvroSchemaComponent > :: 
get_schema_in_ctxt (named_schemas [...]
                 let schema_token_stream = schema_res.unwrap().to_string();
                 assert!(schema_token_stream.contains(expected_token_stream));
             }
@@ -700,7 +671,7 @@ mod tests {
         match syn::parse2::<DeriveInput>(test_struct) {
             Ok(mut input) => {
                 let schema_res = derive_avro_schema(&mut input);
-                let expected_token_stream = r#"let name = apache_avro :: 
schema :: Name :: new ("A") . expect (& format ! ("Unable to parse schema name 
{}" , "A") [..]) . fully_qualified_name (enclosing_namespace) ; let 
enclosing_namespace = & name . namespace ; if named_schemas . contains_key (& 
name) { apache_avro :: schema :: Schema :: Ref { name : name . clone () } } 
else { named_schemas . insert (name . clone () , apache_avro :: schema :: 
Schema :: Ref { name : name . clone () }) ;  [...]
+                let expected_token_stream = r#"let name = apache_avro :: 
schema :: Name :: new ("A") . expect (& format ! ("Unable to parse schema name 
{}" , "A") [..]) . fully_qualified_name (enclosing_namespace) ; let 
enclosing_namespace = & name . namespace ; if named_schemas . contains_key (& 
name) { apache_avro :: schema :: Schema :: Ref { name : name . clone () } } 
else { named_schemas . insert (name . clone () , apache_avro :: schema :: 
Schema :: Ref { name : name . clone () }) ;  [...]
                 let schema_token_stream = schema_res.unwrap().to_string();
                 assert!(schema_token_stream.contains(expected_token_stream));
             }
@@ -744,7 +715,7 @@ mod tests {
         match syn::parse2::<DeriveInput>(test_struct) {
             Ok(mut input) => {
                 let schema_res = derive_avro_schema(&mut input);
-                let expected_token_stream = r#"let name = apache_avro :: 
schema :: Name :: new ("A") . expect (& format ! ("Unable to parse schema name 
{}" , "A") [..]) . fully_qualified_name (enclosing_namespace) ; let 
enclosing_namespace = & name . namespace ; if named_schemas . contains_key (& 
name) { apache_avro :: schema :: Schema :: Ref { name : name . clone () } } 
else { named_schemas . insert (name . clone () , apache_avro :: schema :: 
Schema :: Ref { name : name . clone () }) ;  [...]
+                let expected_token_stream = r#"let name = apache_avro :: 
schema :: Name :: new ("A") . expect (& format ! ("Unable to parse schema name 
{}" , "A") [..]) . fully_qualified_name (enclosing_namespace) ; let 
enclosing_namespace = & name . namespace ; if named_schemas . contains_key (& 
name) { apache_avro :: schema :: Schema :: Ref { name : name . clone () } } 
else { named_schemas . insert (name . clone () , apache_avro :: schema :: 
Schema :: Ref { name : name . clone () }) ;  [...]
                 let schema_token_stream = schema_res.unwrap().to_string();
                 assert!(schema_token_stream.contains(expected_token_stream));
             }
diff --git a/avro_derive/tests/derive.rs b/avro_derive/tests/derive.rs
index cf3be7e..0d4df09 100644
--- a/avro_derive/tests/derive.rs
+++ b/avro_derive/tests/derive.rs
@@ -1827,3 +1827,88 @@ fn avro_rs_247_serde_flatten_support_with_skip() {
         b: 321,
     });
 }
+
+#[test]
+fn avro_rs_401_do_not_match_typename() {
+    #[expect(nonstandard_style, reason = "It needs to be exactly this")]
+    type f32 = f64;
+
+    #[expect(dead_code, reason = "We only check the schema")]
+    #[derive(AvroSchema)]
+    struct Foo {
+        field: f32,
+    }
+
+    let schema = r#"
+    {
+        "type":"record",
+        "name":"Foo",
+        "fields": [
+            {
+                "name":"field",
+                "type":"double"
+            }
+        ]
+    }
+    "#;
+
+    let schema = Schema::parse_str(schema).unwrap();
+    assert_eq!(schema, Foo::get_schema());
+}
+
+#[test]
+fn avro_rs_401_supported_type_variants() {
+    #[expect(dead_code, reason = "We only check the schema")]
+    #[derive(AvroSchema)]
+    struct Foo<'a> {
+        one: f32,
+        two: std::string::String,
+        three: &'static i32,
+        four: &'a str,
+        five: &'a mut f64,
+        six: [u8; 5],
+        seven: [u8],
+    }
+
+    let schema = r#"
+    {
+        "type":"record",
+        "name":"Foo",
+        "fields": [
+            {
+                "name":"one",
+                "type":"float"
+            },
+            {
+                "name":"two",
+                "type":"string"
+            },
+            {
+                "name":"three",
+                "type":"int"
+            },
+            {
+                "name":"four",
+                "type":"string"
+            },
+            {
+                "name":"five",
+                "type":"double"
+            },
+            {
+                "name":"six",
+                "type":"array",
+                "items":"int"
+            },
+            {
+                "name":"seven",
+                "type":"array",
+                "items":"int"
+            }
+        ]
+    }
+    "#;
+
+    let schema = Schema::parse_str(schema).unwrap();
+    assert_eq!(schema, Foo::get_schema());
+}
diff --git a/avro_derive/tests/ui/avro_rs_401_ptr.rs 
b/avro_derive/tests/ui/avro_rs_401_ptr.rs
new file mode 100644
index 0000000..c003279
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_401_ptr.rs
@@ -0,0 +1,25 @@
+// 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 Foo {
+    a: *const String,
+}
+
+pub fn main() {}
diff --git a/avro_derive/tests/ui/avro_rs_401_ptr.stderr 
b/avro_derive/tests/ui/avro_rs_401_ptr.stderr
new file mode 100644
index 0000000..5c9e082
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_401_ptr.stderr
@@ -0,0 +1,5 @@
+error: AvroSchema: derive does not support raw pointers
+  --> tests/ui/avro_rs_401_ptr.rs:22:8
+   |
+22 |     a: *const String,
+   |        ^^^^^^^^^^^^^
diff --git a/avro_derive/tests/ui/avro_rs_401_tuple.rs 
b/avro_derive/tests/ui/avro_rs_401_tuple.rs
new file mode 100644
index 0000000..cf00214
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_401_tuple.rs
@@ -0,0 +1,25 @@
+// 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 Foo {
+    a: (i32, String),
+}
+
+pub fn main() {}
diff --git a/avro_derive/tests/ui/avro_rs_401_tuple.stderr 
b/avro_derive/tests/ui/avro_rs_401_tuple.stderr
new file mode 100644
index 0000000..ffc0378
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_401_tuple.stderr
@@ -0,0 +1,5 @@
+error: AvroSchema: derive does not support tuples
+  --> tests/ui/avro_rs_401_tuple.rs:22:8
+   |
+22 |     a: (i32, String),
+   |        ^^^^^^^^^^^^^
diff --git a/avro_derive/tests/ui/avro_rs_401_unknown_type_variant.rs 
b/avro_derive/tests/ui/avro_rs_401_unknown_type_variant.rs
new file mode 100644
index 0000000..b723703
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_401_unknown_type_variant.rs
@@ -0,0 +1,25 @@
+// 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 Foo {
+    a: fn() -> String,
+}
+
+pub fn main() {}
diff --git a/avro_derive/tests/ui/avro_rs_401_unknown_type_variant.stderr 
b/avro_derive/tests/ui/avro_rs_401_unknown_type_variant.stderr
new file mode 100644
index 0000000..43262cd
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_401_unknown_type_variant.stderr
@@ -0,0 +1,5 @@
+error: AvroSchema: Unexpected type encountered! Please open an issue if this 
kind of type should be supported: Type::BareFn { lifetimes: None, unsafety: 
None, abi: None, fn_token: Fn, paren_token: Paren, inputs: [], variadic: None, 
output: ReturnType::Type(RArrow, Type::Path { qself: None, path: Path { 
leading_colon: None, segments: [PathSegment { ident: Ident { ident: "String", 
span: #0 bytes(882..888) }, arguments: PathArguments::None }] } }) }
+  --> tests/ui/avro_rs_401_unknown_type_variant.rs:22:8
+   |
+22 |     a: fn() -> String,
+   |        ^^^^^^^^^^^^^^

Reply via email to