This is an automated email from the ASF dual-hosted git repository. Kriskras99 pushed a commit to branch refactor/derive_implementation in repository https://gitbox.apache.org/repos/asf/avro-rs.git
commit c601ca952abf5fdd191d05f3f4fd7ffb419fe6bb Author: Kriskras99 <[email protected]> AuthorDate: Sat Jun 20 17:25:18 2026 +0200 refactor: Centralize generating the actual `impl` in the `Implementation` struct This makes it clearer how everything fits together, and allows extending shared logic further (for example, adding generated tests). And because it is not a `TokenStream`, accidentally returning only a schema expression instead of the entire implementation results in a compilation error. --- avro_derive/src/attributes/mod.rs | 29 +++--- avro_derive/src/enums/mod.rs | 58 ++++------- avro_derive/src/enums/plain.rs | 68 +++++++++--- avro_derive/src/fields.rs | 4 +- avro_derive/src/implementation.rs | 114 +++++++++++++++++++++ avro_derive/src/lib.rs | 99 ++++-------------- avro_derive/src/structs.rs | 82 ++++++++++----- avro_derive/tests/derive.rs | 26 +++++ .../avro_3687_basic_enum_with_default_twice.stderr | 14 ++- .../tests/ui/avro_rs_373_rename_all_fields.stderr | 11 +- .../tests/ui/avro_rs_501_non_basic_enum.stderr | 11 +- .../tests/ui/avro_rs_501_tuple_struct.stderr | 4 +- .../tests/ui/avro_rs_501_unit_struct.stderr | 4 +- 13 files changed, 336 insertions(+), 188 deletions(-) diff --git a/avro_derive/src/attributes/mod.rs b/avro_derive/src/attributes/mod.rs index ebb2997..cb037cd 100644 --- a/avro_derive/src/attributes/mod.rs +++ b/avro_derive/src/attributes/mod.rs @@ -31,7 +31,7 @@ pub struct NamedTypeOptions { pub aliases: Vec<String>, pub rename_all: RenameRule, pub transparent: bool, - pub default: TokenStream, + pub default: Option<TokenStream>, } impl NamedTypeOptions { @@ -118,20 +118,19 @@ impl NamedTypeOptions { let doc = avro.doc.or_else(|| extract_rustdoc(attributes)); - let default = match avro.default { - None => quote! { None }, - Some(default_value) => { - let _: serde_json::Value = - serde_json::from_str(&default_value[..]).map_err(|e| { - vec![syn::Error::new( - ident.span(), - format!("Invalid Avro `default` JSON: \n{e}"), - )] - })?; - quote! { - Some(::serde_json::from_str(#default_value).expect(format!("Invalid JSON: {:?}", #default_value).as_str())) - } - } + let default = if let Some(default_value) = avro.default { + let _: serde_json::Value = + serde_json::from_str(default_value.as_str()).map_err(|e| { + vec![syn::Error::new( + ident.span(), + format!("Invalid Avro `default` JSON: \n{e}"), + )] + })?; + Some(quote! { + ::std::option::Option::Some(::serde_json::from_str(#default_value).expect(format!("Invalid JSON: {:?}", #default_value).as_str())) + }) + } else { + None }; Ok(Self { diff --git a/avro_derive/src/enums/mod.rs b/avro_derive/src/enums/mod.rs index 1511f65..843b77b 100644 --- a/avro_derive/src/enums/mod.rs +++ b/avro_derive/src/enums/mod.rs @@ -18,50 +18,30 @@ mod plain; use crate::attributes::NamedTypeOptions; -use proc_macro2::{Ident, Span, TokenStream}; -use syn::{Attribute, DataEnum, Fields, Meta}; +use crate::implementation::Implementation; +use proc_macro2::{Ident, Span}; +use syn::{DataEnum, Fields, Generics}; /// Generate a schema definition for a enum. -pub fn get_data_enum_schema_def( - container_attrs: &NamedTypeOptions, - data_enum: &DataEnum, - ident_span: Span, -) -> Result<TokenStream, Vec<syn::Error>> { - if data_enum.variants.iter().all(|v| Fields::Unit == v.fields) { - plain::schema_def(container_attrs, data_enum, ident_span) +pub fn to_implementation( + input_span: Span, + ident: Ident, + generics: Generics, + container_attrs: NamedTypeOptions, + data: DataEnum, +) -> Result<Implementation, Vec<syn::Error>> { + if container_attrs.transparent { + return Err(vec![syn::Error::new( + input_span, + "AvroSchema: `#[serde(transparent)]` is only supported on structs", + )]); + } + if data.variants.iter().all(|v| Fields::Unit == v.fields) { + plain::to_implementation(input_span, ident, generics, container_attrs, data) } else { Err(vec![syn::Error::new( - ident_span, + input_span, "AvroSchema: derive does not work for enums with non unit structs", )]) } } - -fn default_enum_variant( - data_enum: &DataEnum, - error_span: Span, -) -> Result<Option<String>, Vec<syn::Error>> { - match data_enum - .variants - .iter() - .filter(|v| v.attrs.iter().any(is_default_attr)) - .collect::<Vec<_>>() - { - variants if variants.is_empty() => Ok(None), - single if single.len() == 1 => Ok(Some(single[0].ident.to_string())), - multiple => Err(vec![syn::Error::new( - error_span, - format!( - "Multiple defaults defined: {:?}", - multiple - .iter() - .map(|v| v.ident.to_string()) - .collect::<Vec<String>>() - ), - )]), - } -} - -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")) -} diff --git a/avro_derive/src/enums/plain.rs b/avro_derive/src/enums/plain.rs index 4fb0adb..7dbcdcb 100644 --- a/avro_derive/src/enums/plain.rs +++ b/avro_derive/src/enums/plain.rs @@ -17,25 +17,27 @@ use crate::attributes::{NamedTypeOptions, VariantOptions}; use crate::case::RenameRule; -use crate::enums::default_enum_variant; +use crate::implementation::Implementation; use crate::{aliases, preserve_optional}; -use proc_macro2::{Span, TokenStream}; +use proc_macro2::{Ident, Span}; use quote::quote; use syn::spanned::Spanned; -use syn::{DataEnum, Fields}; +use syn::{Attribute, DataEnum, Fields, Generics, Meta}; -pub fn schema_def( - container_attrs: &NamedTypeOptions, - data_enum: &DataEnum, - ident_span: Span, -) -> Result<TokenStream, Vec<syn::Error>> { +pub fn to_implementation( + input_span: Span, + ident: Ident, + generics: Generics, + container_attrs: NamedTypeOptions, + data: DataEnum, +) -> Result<Implementation, Vec<syn::Error>> { let doc = preserve_optional(container_attrs.doc.as_ref()); let enum_aliases = aliases(&container_attrs.aliases); - if data_enum.variants.iter().all(|v| Fields::Unit == v.fields) { - let default_value = default_enum_variant(data_enum, ident_span)?; + if data.variants.iter().all(|v| Fields::Unit == v.fields) { + let default_value = default_enum_variant(&data, input_span)?; let default = preserve_optional(default_value); let mut symbols = Vec::new(); - for variant in &data_enum.variants { + for variant in data.variants { let field_attrs = VariantOptions::new(&variant.attrs, variant.span())?; let name = match (field_attrs.rename, container_attrs.rename_all) { (Some(rename), _) => rename, @@ -46,7 +48,7 @@ pub fn schema_def( }; symbols.push(name); } - Ok(quote! { + let schema_expr = quote! { ::apache_avro::schema::Schema::Enum(::apache_avro::schema::EnumSchema { name, aliases: #enum_aliases, @@ -55,11 +57,49 @@ pub fn schema_def( default: #default, attributes: ::std::collections::BTreeMap::new(), }) - }) + }; + + Ok(Implementation::named( + ident, + generics, + &container_attrs.name, + schema_expr, + None, + container_attrs.default, + )) } else { Err(vec![syn::Error::new( - ident_span, + input_span, "AvroSchema: derive does not work for enums with non unit structs", )]) } } + +fn default_enum_variant( + data_enum: &DataEnum, + error_span: Span, +) -> Result<Option<String>, Vec<syn::Error>> { + match data_enum + .variants + .iter() + .filter(|v| v.attrs.iter().any(is_default_attr)) + .collect::<Vec<_>>() + { + variants if variants.is_empty() => Ok(None), + single if single.len() == 1 => Ok(Some(single[0].ident.to_string())), + multiple => Err(vec![syn::Error::new( + error_span, + format!( + "AvroSchema: Multiple defaults defined: {:?}", + multiple + .iter() + .map(|v| v.ident.to_string()) + .collect::<Vec<String>>() + ), + )]), + } +} + +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")) +} diff --git a/avro_derive/src/fields.rs b/avro_derive/src/fields.rs index f9acbf1..66c3634 100644 --- a/avro_derive/src/fields.rs +++ b/avro_derive/src/fields.rs @@ -21,7 +21,7 @@ use quote::quote; use syn::spanned::Spanned; use syn::{Expr, Field, Type}; -pub fn get_field_schema_expr(field: &Field, with: With) -> Result<TokenStream, Vec<syn::Error>> { +pub 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) => { @@ -47,7 +47,7 @@ pub fn get_field_schema_expr(field: &Field, with: With) -> Result<TokenStream, V pub fn get_field_get_record_fields_expr( field: &Field, - with: With, + with: &With, ) -> Result<TokenStream, Vec<syn::Error>> { match with { With::Trait => Ok(type_to_get_record_fields_expr(&field.ty)?), diff --git a/avro_derive/src/implementation.rs b/avro_derive/src/implementation.rs new file mode 100644 index 0000000..0124ffd --- /dev/null +++ b/avro_derive/src/implementation.rs @@ -0,0 +1,114 @@ +// 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 proc_macro2::{Ident, TokenStream}; +use quote::quote; +use syn::Generics; + +pub struct Implementation { + ident: Ident, + generics: Generics, + /// An expression that resolves to a `Schema` + /// + /// The variables `named_schemas: &mut HashSet<Name>` and `enclosing_namespace: NamespaceRef` are + /// defined. + schema_expr: TokenStream, + /// An expression that resolves to a `Option<Vec<RecordField>>` + /// + /// The variables `named_schemas: &mut HashSet<Name>` and `enclosing_namespace: NamespaceRef` are + /// defined. + record_fields_expr: TokenStream, + /// An expression that resolves to a `Option<serde_json::Value>` + field_default_expr: TokenStream, +} + +impl Implementation { + #[expect( + clippy::needless_pass_by_value, + reason = "Makes it match the `unnamed` variant" + )] + pub fn named( + ident: Ident, + generics: Generics, + name: &str, + schema_expr: TokenStream, + record_fields_expr: Option<TokenStream>, + field_default_expr: Option<TokenStream>, + ) -> Implementation { + let schema_expr = quote! { + let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(concat!("Unable to parse schema name ", #name)); + if named_schemas.contains(&name) { + ::apache_avro::schema::Schema::Ref{name} + } else { + let enclosing_namespace = name.namespace(); + named_schemas.insert(name.clone()); + #schema_expr + } + }; + + Self::unnamed( + ident, + generics, + schema_expr, + record_fields_expr, + field_default_expr, + ) + } + + pub fn unnamed( + ident: Ident, + generics: Generics, + schema_expr: TokenStream, + record_fields_expr: Option<TokenStream>, + field_default_expr: Option<TokenStream>, + ) -> Implementation { + Self { + ident, + generics, + schema_expr, + record_fields_expr: record_fields_expr + .unwrap_or_else(|| quote! { ::std::option::Option::None }), + field_default_expr: field_default_expr + .unwrap_or_else(|| quote! { ::std::option::Option::None }), + } + } + + pub fn into_token_stream(self) -> TokenStream { + let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); + let ident = self.ident; + let schema_expr = self.schema_expr; + let record_fields_expr = self.record_fields_expr; + let field_default_expr = self.field_default_expr; + + quote! { + #[automatically_derived] + impl #impl_generics ::apache_avro::AvroSchemaComponent for #ident #ty_generics #where_clause { + 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 { + #schema_expr + } + + 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>> { + #record_fields_expr + } + + fn field_default() -> ::std::option::Option<::serde_json::Value> { + #field_default_expr + } + } + } + } +} diff --git a/avro_derive/src/lib.rs b/avro_derive/src/lib.rs index e2bc329..2401eab 100644 --- a/avro_derive/src/lib.rs +++ b/avro_derive/src/lib.rs @@ -33,16 +33,14 @@ mod attributes; mod case; mod enums; mod fields; +mod implementation; mod structs; mod utils; -use proc_macro2::TokenStream; -use quote::quote; -use syn::{DeriveInput, Generics, Ident, parse_macro_input, spanned::Spanned}; +use syn::{DeriveInput, parse_macro_input, spanned::Spanned}; use crate::attributes::NamedTypeOptions; -use crate::enums::get_data_enum_schema_def; -use crate::structs::{get_struct_schema_def, get_transparent_struct_schema_def}; +use crate::implementation::Implementation; use crate::utils::{aliases, preserve_optional, to_compile_errors}; #[proc_macro_derive(AvroSchema, attributes(avro, serde))] @@ -50,53 +48,35 @@ use crate::utils::{aliases, preserve_optional, to_compile_errors}; pub fn proc_macro_derive_avro_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); derive_avro_schema(input) + .map(Implementation::into_token_stream) .unwrap_or_else(to_compile_errors) .into() } -fn derive_avro_schema(input: DeriveInput) -> Result<TokenStream, Vec<syn::Error>> { +fn derive_avro_schema(input: DeriveInput) -> Result<Implementation, Vec<syn::Error>> { // It would be nice to parse the attributes before the `match`, but we first need to validate that `input` is not a union. // Otherwise a user could get errors related to the attributes and after fixing those get an error because the attributes were on a union. let input_span = input.span(); match input.data { syn::Data::Struct(data_struct) => { let named_type_options = NamedTypeOptions::new(&input.ident, &input.attrs, input_span)?; - 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())?; - ( - handle_named_schemas(&named_type_options.name, &schema_def), - record_fields, - ) - }; - Ok(create_trait_definition( - &input.ident, - &input.generics, - &get_schema_impl, - &get_record_fields_impl, - &named_type_options.default, - )) + structs::to_implementation( + input_span, + input.ident, + input.generics, + named_type_options, + data_struct, + ) } syn::Data::Enum(data_enum) => { let named_type_options = NamedTypeOptions::new(&input.ident, &input.attrs, input_span)?; - if named_type_options.transparent { - return Err(vec![syn::Error::new( - input_span, - "AvroSchema: `#[serde(transparent)]` is only supported on structs", - )]); - } - let schema_def = - get_data_enum_schema_def(&named_type_options, &data_enum, input.ident.span())?; - let inner = handle_named_schemas(&named_type_options.name, &schema_def); - Ok(create_trait_definition( - &input.ident, - &input.generics, - &inner, - "e! { ::std::option::Option::None }, - &named_type_options.default, - )) + enums::to_implementation( + input_span, + input.ident, + input.generics, + named_type_options, + data_enum, + ) } syn::Data::Union(_) => Err(vec![syn::Error::new( input_span, @@ -104,44 +84,3 @@ fn derive_avro_schema(input: DeriveInput) -> Result<TokenStream, Vec<syn::Error> )]), } } - -/// Generate the trait definition with the correct generics -fn create_trait_definition( - ident: &Ident, - generics: &Generics, - get_schema_impl: &TokenStream, - get_record_fields_impl: &TokenStream, - field_default_impl: &TokenStream, -) -> TokenStream { - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - quote! { - #[automatically_derived] - impl #impl_generics ::apache_avro::AvroSchemaComponent for #ident #ty_generics #where_clause { - 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 { - #get_schema_impl - } - - 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>> { - #get_record_fields_impl - } - - fn field_default() -> ::std::option::Option<::serde_json::Value> { - ::std::option::Option::#field_default_impl - } - } - } -} - -/// Generate the code to check `named_schemas` if this schema already exist -fn handle_named_schemas(full_schema_name: &str, schema_def: &TokenStream) -> TokenStream { - quote! { - let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(#full_schema_name, enclosing_namespace).expect(concat!("Unable to parse schema name ", #full_schema_name)); - if named_schemas.contains(&name) { - ::apache_avro::schema::Schema::Ref{name} - } else { - let enclosing_namespace = name.namespace(); - named_schemas.insert(name.clone()); - #schema_def - } - } -} diff --git a/avro_derive/src/structs.rs b/avro_derive/src/structs.rs index 53bcbe5..af9f9da 100644 --- a/avro_derive/src/structs.rs +++ b/avro_derive/src/structs.rs @@ -20,20 +20,36 @@ use crate::case::RenameRule; use crate::fields::{ get_field_field_default_expr, get_field_get_record_fields_expr, get_field_schema_expr, }; +use crate::implementation::Implementation; use crate::utils::{aliases, field_aliases, preserve_optional}; -use proc_macro2::{Span, TokenStream}; +use proc_macro2::{Ident, Span}; use quote::quote; use syn::spanned::Spanned; -use syn::{DataStruct, Fields}; +use syn::{DataStruct, Fields, Generics}; -/// Generate a schema definition for a struct. -pub fn get_struct_schema_def( - container_attrs: &NamedTypeOptions, - data_struct: DataStruct, - ident_span: Span, -) -> Result<(TokenStream, TokenStream), Vec<syn::Error>> { +pub fn to_implementation( + input_span: Span, + ident: Ident, + generics: Generics, + container_attrs: NamedTypeOptions, + data: DataStruct, +) -> Result<Implementation, Vec<syn::Error>> { + if container_attrs.transparent { + transparent(input_span, ident, generics, container_attrs, data) + } else { + normal(input_span, ident, generics, container_attrs, data) + } +} + +fn normal( + input_span: Span, + ident: Ident, + generics: Generics, + container_attrs: NamedTypeOptions, + data: DataStruct, +) -> Result<Implementation, Vec<syn::Error>> { let mut record_field_exprs = vec![]; - match data_struct.fields { + match data.fields { Fields::Named(a) => { for field in a.named { let mut name = field @@ -61,7 +77,7 @@ pub fn get_struct_schema_def( // 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)?; + 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); @@ -75,7 +91,7 @@ pub fn get_struct_schema_def( } let default_value = get_field_field_default_expr(&field, field_attrs.default)?; let aliases = field_aliases(&field_attrs.alias); - let schema_expr = get_field_schema_expr(&field, field_attrs.with)?; + 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(), @@ -90,13 +106,13 @@ pub fn get_struct_schema_def( } Fields::Unnamed(_) => { return Err(vec![syn::Error::new( - ident_span, + input_span, "AvroSchema derive does not work for tuple structs", )]); } Fields::Unit => { return Err(vec![syn::Error::new( - ident_span, + input_span, "AvroSchema derive does not work for unit structs", )]); } @@ -110,7 +126,7 @@ pub fn get_struct_schema_def( // the most common case where there is no flatten. let minimum_fields = record_field_exprs.len(); - let schema_def = quote! { + let schema_expr = quote! { { let mut schema_fields = ::std::vec::Vec::with_capacity(#minimum_fields); #(#record_field_exprs)* @@ -132,21 +148,30 @@ pub fn get_struct_schema_def( }) } }; - let record_fields = quote! { + let record_fields_expr = quote! { let mut schema_fields = ::std::vec::Vec::with_capacity(#minimum_fields); #(#record_field_exprs)* ::std::option::Option::Some(schema_fields) }; - Ok((schema_def, record_fields)) + Ok(Implementation::named( + ident, + generics, + &container_attrs.name, + schema_expr, + Some(record_fields_expr), + container_attrs.default, + )) } -/// Use the schema definition of the only field in the struct as the schema -pub fn get_transparent_struct_schema_def( - fields: Fields, +fn transparent( input_span: Span, -) -> Result<(TokenStream, TokenStream), Vec<syn::Error>> { - match fields { + ident: Ident, + generics: Generics, + container_attrs: NamedTypeOptions, + data: DataStruct, +) -> Result<Implementation, Vec<syn::Error>> { + match data.fields { Fields::Named(fields_named) => { let mut found = None; for field in fields_named.named { @@ -163,9 +188,18 @@ pub 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)?, + let field_default_expr = if container_attrs.default.is_none() { + Some(get_field_field_default_expr(&field, attrs.default)?) + } else { + container_attrs.default + }; + + Ok(Implementation::unnamed( + ident, + generics, + get_field_schema_expr(&field, &attrs.with)?, + Some(get_field_get_record_fields_expr(&field, &attrs.with)?), + field_default_expr, )) } else { Err(vec![syn::Error::new( diff --git a/avro_derive/tests/derive.rs b/avro_derive/tests/derive.rs index e2509c3..9da6851 100644 --- a/avro_derive/tests/derive.rs +++ b/avro_derive/tests/derive.rs @@ -2570,3 +2570,29 @@ fn avro_rs_476_skip_serializing_fielddefault_trait_none() { }, } } + +#[test] +fn avro_rs_561_transparent_struct_with_default_override() { + #[derive(AvroSchema)] + #[serde(transparent)] + struct Ta { + #[avro(default = "0")] + _field: i32, + } + #[derive(AvroSchema)] + #[serde(transparent)] + #[avro(default = "0")] + struct Tb { + _field: i32, + } + + let schema = Ta::get_schema(); + let field_default = Ta::field_default(); + assert_eq!(schema, Schema::Int); + assert_eq!(field_default, Some(serde_json::Value::Number(0i32.into()))); + + let schema = Tb::get_schema(); + let field_default = Tb::field_default(); + assert_eq!(schema, Schema::Int); + assert_eq!(field_default, Some(serde_json::Value::Number(0i32.into()))); +} diff --git a/avro_derive/tests/ui/avro_3687_basic_enum_with_default_twice.stderr b/avro_derive/tests/ui/avro_3687_basic_enum_with_default_twice.stderr index 14a3798..e8e97e6 100644 --- a/avro_derive/tests/ui/avro_3687_basic_enum_with_default_twice.stderr +++ b/avro_derive/tests/ui/avro_3687_basic_enum_with_default_twice.stderr @@ -1,8 +1,14 @@ -error: Multiple defaults defined: ["A", "C"] - --> tests/ui/avro_3687_basic_enum_with_default_twice.rs:21:6 +error: AvroSchema: Multiple defaults defined: ["A", "C"] + --> tests/ui/avro_3687_basic_enum_with_default_twice.rs:21:1 | -21 | enum Basic { - | ^^^^^ +21 | / enum Basic { +22 | | #[default] +23 | | A, +24 | | B, +... | +27 | | D +28 | | } + | |_^ error: multiple declared defaults --> tests/ui/avro_3687_basic_enum_with_default_twice.rs:20:22 diff --git a/avro_derive/tests/ui/avro_rs_373_rename_all_fields.stderr b/avro_derive/tests/ui/avro_rs_373_rename_all_fields.stderr index 7a5a531..c779c05 100644 --- a/avro_derive/tests/ui/avro_rs_373_rename_all_fields.stderr +++ b/avro_derive/tests/ui/avro_rs_373_rename_all_fields.stderr @@ -1,5 +1,10 @@ error: AvroSchema: derive does not work for enums with non unit structs - --> tests/ui/avro_rs_373_rename_all_fields.rs:22:6 + --> tests/ui/avro_rs_373_rename_all_fields.rs:21:1 | -22 | enum Foo { - | ^^^ +21 | / #[serde(rename_all_fields = "UPPERCASE")] +22 | | enum Foo { +23 | | Bar { +24 | | a: String, +... | +27 | | } + | |_^ 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 index 961253b..2ef79de 100644 --- a/avro_derive/tests/ui/avro_rs_501_non_basic_enum.stderr +++ b/avro_derive/tests/ui/avro_rs_501_non_basic_enum.stderr @@ -1,5 +1,10 @@ error: AvroSchema: derive does not work for enums with non unit structs - --> tests/ui/avro_rs_501_non_basic_enum.rs:21:6 + --> tests/ui/avro_rs_501_non_basic_enum.rs:21:1 | -21 | enum NonBasic { - | ^^^^^^^^ +21 | / enum NonBasic { +22 | | A(i32), +23 | | B, +24 | | C, +25 | | D +26 | | } + | |_^ diff --git a/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr b/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr index 1091ec0..5051fc7 100644 --- a/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr +++ b/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr @@ -1,5 +1,5 @@ error: AvroSchema derive does not work for tuple structs - --> tests/ui/avro_rs_501_tuple_struct.rs:21:8 + --> tests/ui/avro_rs_501_tuple_struct.rs:21:1 | 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 index 2a16ef6..655af14 100644 --- a/avro_derive/tests/ui/avro_rs_501_unit_struct.stderr +++ b/avro_derive/tests/ui/avro_rs_501_unit_struct.stderr @@ -1,5 +1,5 @@ error: AvroSchema derive does not work for unit structs - --> tests/ui/avro_rs_501_unit_struct.rs:21:8 + --> tests/ui/avro_rs_501_unit_struct.rs:21:1 | 21 | struct AbsoluteUnit; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^
