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,
+ | ^^^^^^^^^^^^^^