This is an automated email from the ASF dual-hosted git repository. kriskras99 pushed a commit to branch fix/derive_string_matching in repository https://gitbox.apache.org/repos/asf/avro-rs.git
commit 57867cc5ac49e80189efe78596008a520d248684 Author: Kriskras99 <[email protected]> AuthorDate: Tue Jan 13 22:21:18 2026 +0100 fix(derive): do not match type by name --- avro/src/schema.rs | 1 + avro_derive/src/lib.rs | 37 ++++++------------------------------- avro_derive/tests/derive.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/avro/src/schema.rs b/avro/src/schema.rs index 809606a..204a3af 100644 --- a/avro/src/schema.rs +++ b/avro/src/schema.rs @@ -2657,6 +2657,7 @@ 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 Vec<T> diff --git a/avro_derive/src/lib.rs b/avro_derive/src/lib.rs index c3587ed..aea8ea5 100644 --- a/avro_derive/src/lib.rs +++ b/avro_derive/src/lib.rs @@ -267,34 +267,9 @@ 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) + // If the type does not implement AvroSchemaComponent this will cause a compile error + // indicating that + Ok(type_path_schema_expr(p)) } 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)}) @@ -658,7 +633,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 +675,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 +719,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..ec8e705 100644 --- a/avro_derive/tests/derive.rs +++ b/avro_derive/tests/derive.rs @@ -1827,3 +1827,31 @@ 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()); +}
