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 285f5c9 feat: Use `macrotest` to test the expanded macro code (#501)
285f5c9 is described below
commit 285f5c90d0b1b1417cc912cc853faa364134725c
Author: Kriskras99 <[email protected]>
AuthorDate: Thu Mar 5 22:24:39 2026 +0100
feat: Use `macrotest` to test the expanded macro code (#501)
* feat: Use `macrotest` to test the expanded macro code
* fix: Expanded files are missing license header
* fix: Steps don't share anything
* fix: Use `taiki-e/install-action` to install `cargo-rdme` and
`cargo-expand`
* fix: Typo in documentation
Co-authored-by: Martin Grigorov <[email protected]>
* fix: Only install `cargo-rdme` on `stable-x86_64` and `cargo-expand` on
`nightly`
* fix: Apply suggestions from code review
Co-authored-by: Martin Grigorov <[email protected]>
* fix: Use more full paths
---------
Co-authored-by: default <[email protected]>
Co-authored-by: Martin Grigorov <[email protected]>
---
.github/workflows/test-lang-rust-ci.yml | 22 +-
Cargo.lock | 24 ++
avro_derive/Cargo.toml | 1 +
avro_derive/src/enums/plain.rs | 7 +-
avro_derive/src/lib.rs | 384 +--------------------
avro_derive/tests/expand.rs | 28 ++
.../avro_3687_basic_enum_with_default.expanded.rs | 59 ++++
.../expanded/avro_3687_basic_enum_with_default.rs | 28 ++
.../avro_3709_record_field_attributes.expanded.rs | 178 ++++++++++
.../expanded/avro_3709_record_field_attributes.rs | 32 ++
.../avro_rs_207_rename_all_attribute.expanded.rs | 180 ++++++++++
.../expanded/avro_rs_207_rename_all_attribute.rs | 32 ++
...name_attr_over_rename_all_attribute.expanded.rs | 133 +++++++
...rs_207_rename_attr_over_rename_all_attribute.rs | 26 ++
.../tests/expanded/avro_rs_501_basic.expanded.rs | 180 ++++++++++
avro_derive/tests/expanded/avro_rs_501_basic.rs | 32 ++
.../expanded/avro_rs_501_namespace.expanded.rs | 133 +++++++
.../tests/expanded/avro_rs_501_namespace.rs | 25 ++
.../expanded/avro_rs_501_reference.expanded.rs | 139 ++++++++
.../tests/expanded/avro_rs_501_reference.rs | 24 ++
.../avro_rs_501_struct_with_optional.expanded.rs | 115 ++++++
.../expanded/avro_rs_501_struct_with_optional.rs | 23 ++
avro_derive/tests/expanded/mod.rs | 29 ++
.../ui/avro_3687_basic_enum_with_default_twice.rs | 30 ++
.../avro_3687_basic_enum_with_default_twice.stderr | 19 +
avro_derive/tests/ui/avro_rs_501_non_basic_enum.rs | 28 ++
.../tests/ui/avro_rs_501_non_basic_enum.stderr | 5 +
avro_derive/tests/ui/avro_rs_501_tuple_struct.rs | 23 ++
.../tests/ui/avro_rs_501_tuple_struct.stderr | 5 +
avro_derive/tests/ui/avro_rs_501_unit_struct.rs | 23 ++
.../tests/ui/avro_rs_501_unit_struct.stderr | 5 +
licenserc.toml | 1 +
32 files changed, 1586 insertions(+), 387 deletions(-)
diff --git a/.github/workflows/test-lang-rust-ci.yml
b/.github/workflows/test-lang-rust-ci.yml
index 431ff7c..380366b 100644
--- a/.github/workflows/test-lang-rust-ci.yml
+++ b/.github/workflows/test-lang-rust-ci.yml
@@ -61,6 +61,16 @@ jobs:
target: aarch64-unknown-linux-gnu
steps:
+ - uses: taiki-e/install-action@v2
+ if: matrix.rust == 'nightly'
+ with:
+ tool: cargo-expand
+
+ - uses: taiki-e/install-action@v2
+ if: matrix.rust == 'stable' && matrix.runner.target ==
'x86_64-unknown-linux-gnu'
+ with:
+ tool: cargo-rdme
+
- name: Checkout
uses: actions/checkout@v6
@@ -86,21 +96,11 @@ jobs:
components: rustfmt
targets: ${{ matrix.runner.target }}
- - name: Cache cargo-rdme
- if: matrix.rust == 'stable' && matrix.runner.target ==
'x86_64-unknown-linux-gnu'
- uses: actions/cache@v5
- with:
- path: ~/.cargo-${{ matrix.rust }}/cargo-rdme
- key: cargo-rdme-
-
# Check if the doc cumment in avro/src/lib.rs and avro/README.md are in
sync.
- name: Run cargo-rdme
# The result is environment independent so one test pattern is enough.
if: matrix.rust == 'stable' && matrix.runner.target ==
'x86_64-unknown-linux-gnu'
- run: |
- cargo install --root ~/.cargo-${{ matrix.rust }}/cargo-rdme --locked
cargo-rdme
- export PATH=$PATH:~/.cargo-${{ matrix.rust }}/cargo-rdme/bin
- cargo rdme --check
+ run: cargo rdme --check
- name: Rust Format
if: matrix.runner.target != 'wasm32-unknown-unknown'
diff --git a/Cargo.lock b/Cargo.lock
index bc2d38a..3accbf6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -101,6 +101,7 @@ version = "0.22.0"
dependencies = [
"apache-avro",
"darling",
+ "macrotest",
"pretty_assertions",
"proc-macro2",
"proptest",
@@ -537,6 +538,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@@ -785,6 +792,23 @@ version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+[[package]]
+name = "macrotest"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd198afd908012e57564b66e43e7d4d19056cec7e6232e9e6d54a1798622f81d"
+dependencies = [
+ "diff",
+ "fastrand",
+ "glob",
+ "prettyplease",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "syn",
+ "toml",
+]
+
[[package]]
name = "md-5"
version = "0.10.6"
diff --git a/avro_derive/Cargo.toml b/avro_derive/Cargo.toml
index c86f9d6..c8495da 100644
--- a/avro_derive/Cargo.toml
+++ b/avro_derive/Cargo.toml
@@ -41,6 +41,7 @@ uuid = { workspace = true }
[dev-dependencies]
apache-avro = { default-features = false, path = "../avro", features =
["derive"] }
+macrotest = { version = "1.2.1", default-features = false }
pretty_assertions = { workspace = true }
proptest = { default-features = false, version = "1.10.0", features = ["std"] }
rustversion = "1.0.22"
diff --git a/avro_derive/src/enums/plain.rs b/avro_derive/src/enums/plain.rs
index 89de59c..2832c08 100644
--- a/avro_derive/src/enums/plain.rs
+++ b/avro_derive/src/enums/plain.rs
@@ -46,15 +46,14 @@ pub fn schema_def(
};
symbols.push(name);
}
- let full_schema_name = &container_attrs.name;
Ok(quote! {
-
::apache_avro::schema::Schema::Enum(apache_avro::schema::EnumSchema {
- name:
::apache_avro::schema::Name::new(#full_schema_name).expect(&format!("Unable to
parse enum name for schema {}", #full_schema_name)[..]),
+
::apache_avro::schema::Schema::Enum(::apache_avro::schema::EnumSchema {
+ name,
aliases: #enum_aliases,
doc: #doc,
symbols: vec![#(#symbols.to_owned()),*],
default: #default,
- attributes: Default::default(),
+ attributes: ::std::collections::BTreeMap::new(),
})
})
} else {
diff --git a/avro_derive/src/lib.rs b/avro_derive/src/lib.rs
index 52de29b..96f997e 100644
--- a/avro_derive/src/lib.rs
+++ b/avro_derive/src/lib.rs
@@ -95,7 +95,7 @@ fn derive_avro_schema(input: DeriveInput) ->
Result<TokenStream, Vec<syn::Error>
input.ident,
&input.generics,
inner,
- quote! { None },
+ quote! { ::std::option::Option::None },
named_type_options.default,
))
}
@@ -195,7 +195,7 @@ fn get_struct_schema_def(
continue;
}
let default_value = match field_attrs.default {
- FieldDefault::Disabled => quote! { None },
+ FieldDefault::Disabled => quote! {
::std::option::Option::None },
FieldDefault::Trait =>
type_to_field_default_expr(&field.ty)?,
FieldDefault::Value(default_value) => {
let _: serde_json::Value =
serde_json::from_str(&default_value[..])
@@ -206,7 +206,7 @@ fn get_struct_schema_def(
)]
})?;
quote! {
-
Some(::serde_json::from_str(#default_value).expect(format!("Invalid JSON:
{:?}", #default_value).as_str()))
+
::std::option::Option::Some(::serde_json::from_str(#default_value).expect("Unreachable!
This parsed at compile time!"))
}
}
};
@@ -219,7 +219,7 @@ fn get_struct_schema_def(
default: #default_value,
aliases: #aliases,
schema: #schema_expr,
- custom_attributes: Default::default(),
+ custom_attributes: ::std::collections::BTreeMap::new(),
});
});
}
@@ -248,30 +248,30 @@ fn get_struct_schema_def(
let schema_def = quote! {
{
- let mut schema_fields = Vec::with_capacity(#minimum_fields);
+ let mut schema_fields =
::std::vec::Vec::with_capacity(#minimum_fields);
#(#record_field_exprs)*
let schema_field_set: ::std::collections::HashSet<_> =
schema_fields.iter().map(|rf| &rf.name).collect();
assert_eq!(schema_fields.len(), schema_field_set.len(), "Duplicate
field names found: {schema_fields:?}");
let name =
::apache_avro::schema::Name::new(#full_schema_name).expect(&format!("Unable to
parse struct name for schema {}", #full_schema_name)[..]);
- let lookup: std::collections::BTreeMap<String, usize> =
schema_fields
+ let lookup: ::std::collections::BTreeMap<String, usize> =
schema_fields
.iter()
.enumerate()
.map(|(position, field)| (field.name.to_owned(), position))
.collect();
-
::apache_avro::schema::Schema::Record(apache_avro::schema::RecordSchema {
+
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema {
name,
aliases: #record_aliases,
doc: #record_doc,
fields: schema_fields,
lookup,
- attributes: Default::default(),
+ attributes: ::std::collections::BTreeMap::new(),
})
}
};
let record_fields = quote! {
- let mut schema_fields = Vec::with_capacity(#minimum_fields);
+ let mut schema_fields =
::std::vec::Vec::with_capacity(#minimum_fields);
#(#record_field_exprs)*
- Some(schema_fields)
+ ::std::option::Option::Some(schema_fields)
};
Ok((schema_def, record_fields))
@@ -455,8 +455,8 @@ fn to_compile_errors(errors: Vec<syn::Error>) ->
proc_macro2::TokenStream {
fn preserve_optional(op: Option<impl quote::ToTokens>) -> TokenStream {
match op {
- Some(tt) => quote! {Some(#tt.into())},
- None => quote! {None},
+ Some(tt) => quote! {::std::option::Option::Some(#tt.into())},
+ None => quote! {::std::option::Option::None},
}
}
@@ -489,370 +489,10 @@ mod tests {
use super::*;
use pretty_assertions::assert_eq;
- #[test]
- fn basic_case() {
- let test_struct = quote! {
- struct A {
- a: i32,
- b: String
- }
- };
-
- match syn::parse2::<DeriveInput>(test_struct) {
- Ok(input) => {
- assert!(derive_avro_schema(input).is_ok())
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn tuple_struct_unsupported() {
- let test_tuple_struct = quote! {
- struct B (i32, String);
- };
-
- match syn::parse2::<DeriveInput>(test_tuple_struct) {
- Ok(input) => {
- assert!(derive_avro_schema(input).is_err())
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn unit_struct_unsupported() {
- let test_tuple_struct = quote! {
- struct AbsoluteUnit;
- };
-
- match syn::parse2::<DeriveInput>(test_tuple_struct) {
- Ok(input) => {
- assert!(derive_avro_schema(input).is_err())
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn struct_with_optional() {
- let struct_with_optional = quote! {
- struct Test4 {
- a : Option<i32>
- }
- };
- match syn::parse2::<DeriveInput>(struct_with_optional) {
- Ok(input) => {
- assert!(derive_avro_schema(input).is_ok())
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn test_basic_enum() {
- let basic_enum = quote! {
- enum Basic {
- A,
- B,
- C,
- D
- }
- };
- match syn::parse2::<DeriveInput>(basic_enum) {
- Ok(input) => {
- assert!(derive_avro_schema(input).is_ok())
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn avro_3687_basic_enum_with_default() {
- let basic_enum = quote! {
- enum Basic {
- #[default]
- A,
- B,
- C,
- D
- }
- };
- match syn::parse2::<DeriveInput>(basic_enum) {
- Ok(input) => {
- let derived = derive_avro_schema(input);
- assert!(derived.is_ok());
- assert_eq!(derived.unwrap().to_string(), quote! {
- #[automatically_derived]
- impl ::apache_avro::AvroSchemaComponent for Basic {
- 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 {
- let name =
::apache_avro::schema::Name::new_with_enclosing_namespace("Basic",
enclosing_namespace)
- .expect(concat!("Unable to parse schema name
", "Basic"));
- if named_schemas.contains(&name) {
- ::apache_avro::schema::Schema::Ref { name }
- } else {
- let enclosing_namespace = name.namespace();
- named_schemas.insert(name.clone());
-
::apache_avro::schema::Schema::Enum(apache_avro::schema::EnumSchema {
- name:
::apache_avro::schema::Name::new("Basic").expect(
- &format!("Unable to parse enum name
for schema {}", "Basic")[..]
- ),
- aliases: ::std::option::Option::None,
- doc: None,
- symbols: vec![
- "A".to_owned(),
- "B".to_owned(),
- "C".to_owned(),
- "D".to_owned()
- ],
- default: Some("A".into()),
- attributes: Default::default(),
- })
- }
- }
-
- 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>> {
- None
- }
-
- fn field_default () ->
::std::option::Option<::serde_json::Value> {
- ::std::option::Option::None
- }
- }
- }.to_string());
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn avro_3687_basic_enum_with_default_twice() {
- let non_basic_enum = quote! {
- enum Basic {
- #[default]
- A,
- B,
- #[default]
- C,
- D
- }
- };
- match syn::parse2::<DeriveInput>(non_basic_enum) {
- Ok(input) => match derive_avro_schema(input) {
- Ok(_) => {
- panic!("Should not be able to derive schema for enum with
multiple defaults")
- }
- Err(errors) => {
- assert_eq!(errors.len(), 1);
- assert_eq!(
- errors[0].to_string(),
- r#"Multiple defaults defined: ["A", "C"]"#
- );
- }
- },
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn test_non_basic_enum() {
- let non_basic_enum = quote! {
- enum Basic {
- A(i32),
- B,
- C,
- D
- }
- };
- match syn::parse2::<DeriveInput>(non_basic_enum) {
- Ok(input) => {
- assert!(derive_avro_schema(input).is_err())
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn test_namespace() {
- let test_struct = quote! {
- #[avro(namespace = "namespace.testing")]
- struct A {
- a: i32,
- b: String
- }
- };
-
- match syn::parse2::<DeriveInput>(test_struct) {
- Ok(input) => {
- let schema_token_stream = derive_avro_schema(input);
- assert!(&schema_token_stream.is_ok());
- assert!(
- schema_token_stream
- .unwrap()
- .to_string()
- .contains("namespace.testing")
- )
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn test_reference() {
- let test_reference_struct = quote! {
- struct A<'a> {
- a: &'a Vec<i32>,
- b: &'static str
- }
- };
-
- match syn::parse2::<DeriveInput>(test_reference_struct) {
- Ok(input) => {
- assert!(derive_avro_schema(input).is_ok())
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
#[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());
}
-
- #[test]
- fn test_avro_3709_record_field_attributes() {
- let test_struct = quote! {
- struct A {
- #[serde(alias = "a1", alias = "a2", rename = "a3")]
- #[avro(doc = "a doc", default = "123")]
- a: i32
- }
- };
-
- match syn::parse2::<DeriveInput>(test_struct) {
- Ok(input) => {
- let schema_res = derive_avro_schema(input);
- let expected_token_stream = r#"# [automatically_derived] impl
:: apache_avro :: AvroSchemaComponent for A { 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 { let name = :: apache_avro
:: schema :: Name :: new_with_enclosing_namespace ("A" , enclosing_namespace) .
expect (concat ! ("Unable to parse schema [...]
- let schema_token_stream = schema_res.unwrap().to_string();
- assert_eq!(schema_token_stream, expected_token_stream);
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
-
- let test_enum = quote! {
- enum A {
- #[serde(rename = "A3")]
- Item1,
- }
- };
-
- match syn::parse2::<DeriveInput>(test_enum) {
- Ok(input) => {
- let schema_res = derive_avro_schema(input);
- let expected_token_stream = r#"# [automatically_derived] impl
:: apache_avro :: AvroSchemaComponent for A { 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 { let name = :: apache_avro
:: schema :: Name :: new_with_enclosing_namespace ("A" , enclosing_namespace) .
expect (concat ! ("Unable to parse schema [...]
- let schema_token_stream = schema_res.unwrap().to_string();
- assert_eq!(schema_token_stream, expected_token_stream);
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn test_avro_rs_207_rename_all_attribute() {
- let test_struct = quote! {
- #[serde(rename_all="SCREAMING_SNAKE_CASE")]
- struct A {
- item: i32,
- double_item: i32
- }
- };
-
- match syn::parse2::<DeriveInput>(test_struct) {
- Ok(input) => {
- let schema_res = derive_avro_schema(input);
- let expected_token_stream = r#"# [automatically_derived] impl
:: apache_avro :: AvroSchemaComponent for A { 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 { let name = :: apache_avro
:: schema :: Name :: new_with_enclosing_namespace ("A" , enclosing_namespace) .
expect (concat ! ("Unable to parse schema [...]
- let schema_token_stream = schema_res.unwrap().to_string();
- assert_eq!(schema_token_stream, expected_token_stream);
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
-
- let test_enum = quote! {
- #[serde(rename_all="SCREAMING_SNAKE_CASE")]
- enum B {
- Item,
- DoubleItem,
- }
- };
-
- match syn::parse2::<DeriveInput>(test_enum) {
- Ok(input) => {
- let schema_res = derive_avro_schema(input);
- let expected_token_stream = r#"# [automatically_derived] impl
:: apache_avro :: AvroSchemaComponent for B { 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 { let name = :: apache_avro
:: schema :: Name :: new_with_enclosing_namespace ("B" , enclosing_namespace) .
expect (concat ! ("Unable to parse schema [...]
- let schema_token_stream = schema_res.unwrap().to_string();
- assert_eq!(schema_token_stream, expected_token_stream);
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
-
- #[test]
- fn test_avro_rs_207_rename_attr_has_priority_over_rename_all_attribute() {
- let test_struct = quote! {
- #[serde(rename_all="SCREAMING_SNAKE_CASE")]
- struct A {
- item: i32,
- #[serde(rename="DoubleItem")]
- double_item: i32
- }
- };
-
- match syn::parse2::<DeriveInput>(test_struct) {
- Ok(input) => {
- let schema_res = derive_avro_schema(input);
- let expected_token_stream = r#"# [automatically_derived] impl
:: apache_avro :: AvroSchemaComponent for A { 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 { let name = :: apache_avro
:: schema :: Name :: new_with_enclosing_namespace ("A" , enclosing_namespace) .
expect (concat ! ("Unable to parse schema [...]
- let schema_token_stream = schema_res.unwrap().to_string();
- assert_eq!(schema_token_stream, expected_token_stream);
- }
- Err(error) => panic!(
- "Failed to parse as derive input when it should be able to.
Error: {error:?}"
- ),
- };
- }
}
diff --git a/avro_derive/tests/expand.rs b/avro_derive/tests/expand.rs
new file mode 100644
index 0000000..6ff76b7
--- /dev/null
+++ b/avro_derive/tests/expand.rs
@@ -0,0 +1,28 @@
+// 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.
+
+// By including the (unexpanded) modules, we can also test that the
+// generated code is valid.
+mod expanded;
+
+/// These tests only run on nightly as the output can change per compiler
version.
+/// Use `MACROTEST=overwrite cargo +nightly test expand` to re-generate them
+#[rustversion::attr(not(nightly), ignore)]
+#[test]
+fn expand() {
+ macrotest::expand("tests/expanded/avro_*.rs");
+}
diff --git
a/avro_derive/tests/expanded/avro_3687_basic_enum_with_default.expanded.rs
b/avro_derive/tests/expanded/avro_3687_basic_enum_with_default.expanded.rs
new file mode 100644
index 0000000..62fcff7
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_3687_basic_enum_with_default.expanded.rs
@@ -0,0 +1,59 @@
+use apache_avro::AvroSchema;
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+enum Basic {
+ #[default]
+ A,
+ B,
+ C,
+ D,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for Basic {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "Basic",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name Basic");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+
::apache_avro::schema::Schema::Enum(::apache_avro::schema::EnumSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ symbols: ::alloc::boxed::box_assume_init_into_vec_unsafe(
+ ::alloc::intrinsics::write_box_via_move(
+ ::alloc::boxed::Box::new_uninit(),
+ ["A".to_owned(), "B".to_owned(), "C".to_owned(),
"D".to_owned()],
+ ),
+ ),
+ default: ::std::option::Option::Some("A".into()),
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ 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>> {
+ ::std::option::Option::None
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
+#[automatically_derived]
+impl ::core::default::Default for Basic {
+ #[inline]
+ fn default() -> Basic {
+ Self::A
+ }
+}
diff --git a/avro_derive/tests/expanded/avro_3687_basic_enum_with_default.rs
b/avro_derive/tests/expanded/avro_3687_basic_enum_with_default.rs
new file mode 100644
index 0000000..21f2617
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_3687_basic_enum_with_default.rs
@@ -0,0 +1,28 @@
+// 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, Default)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+enum Basic {
+ #[default]
+ A,
+ B,
+ C,
+ D,
+}
diff --git
a/avro_derive/tests/expanded/avro_3709_record_field_attributes.expanded.rs
b/avro_derive/tests/expanded/avro_3709_record_field_attributes.expanded.rs
new file mode 100644
index 0000000..0d35f4b
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_3709_record_field_attributes.expanded.rs
@@ -0,0 +1,178 @@
+use apache_avro::AvroSchema;
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+struct A {
+ #[serde(alias = "a1", alias = "a2", rename = "a3")]
+ #[avro(doc = "a doc", default = "123")]
+ a: i32,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for A {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "A",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name A");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+ {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(1usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a3".to_string(),
+ doc: ::std::option::Option::Some("a doc".into()),
+ default: ::std::option::Option::Some(
+ ::serde_json::from_str("123")
+ .expect("Unreachable! This parsed at compile
time!"),
+ ),
+ aliases:
::alloc::boxed::box_assume_init_into_vec_unsafe(
+ ::alloc::intrinsics::write_box_via_move(
+ ::alloc::boxed::Box::new_uninit(),
+ [
+ "a1".try_into().expect("Alias is invalid"),
+ "a2".try_into().expect("Alias is invalid"),
+ ],
+ ),
+ ),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ let schema_field_set: ::std::collections::HashSet<_> =
schema_fields
+ .iter()
+ .map(|rf| &rf.name)
+ .collect();
+ match (&schema_fields.len(), &schema_field_set.len()) {
+ (left_val, right_val) => {
+ if !(*left_val == *right_val) {
+ let kind = ::core::panicking::AssertKind::Eq;
+ ::core::panicking::assert_failed(
+ kind,
+ &*left_val,
+ &*right_val,
+ ::core::option::Option::Some(
+ format_args!(
+ "Duplicate field names found: {0:?}",
schema_fields,
+ ),
+ ),
+ );
+ }
+ }
+ };
+ let name = ::apache_avro::schema::Name::new("A")
+ .expect(
+ &::alloc::__export::must_use({
+ ::alloc::fmt::format(
+ format_args!(
+ "Unable to parse struct name for schema
{0}", "A",
+ ),
+ )
+ })[..],
+ );
+ let lookup: ::std::collections::BTreeMap<String, usize> =
schema_fields
+ .iter()
+ .enumerate()
+ .map(|(position, field)| (field.name.to_owned(), position))
+ .collect();
+
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ fields: schema_fields,
+ lookup,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ }
+ 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>> {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(1usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a3".to_string(),
+ doc: ::std::option::Option::Some("a doc".into()),
+ default: ::std::option::Option::Some(
+ ::serde_json::from_str("123")
+ .expect("Unreachable! This parsed at compile time!"),
+ ),
+ aliases: ::alloc::boxed::box_assume_init_into_vec_unsafe(
+ ::alloc::intrinsics::write_box_via_move(
+ ::alloc::boxed::Box::new_uninit(),
+ [
+ "a1".try_into().expect("Alias is invalid"),
+ "a2".try_into().expect("Alias is invalid"),
+ ],
+ ),
+ ),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ ::std::option::Option::Some(schema_fields)
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
+enum B {
+ #[serde(rename = "A3")]
+ Item1,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for B {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "B",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name B");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+
::apache_avro::schema::Schema::Enum(::apache_avro::schema::EnumSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ symbols: ::alloc::boxed::box_assume_init_into_vec_unsafe(
+ ::alloc::intrinsics::write_box_via_move(
+ ::alloc::boxed::Box::new_uninit(),
+ ["A3".to_owned()],
+ ),
+ ),
+ default: ::std::option::Option::None,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ 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>> {
+ ::std::option::Option::None
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
diff --git a/avro_derive/tests/expanded/avro_3709_record_field_attributes.rs
b/avro_derive/tests/expanded/avro_3709_record_field_attributes.rs
new file mode 100644
index 0000000..240d71a
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_3709_record_field_attributes.rs
@@ -0,0 +1,32 @@
+// 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)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+struct A {
+ #[serde(alias = "a1", alias = "a2", rename = "a3")]
+ #[avro(doc = "a doc", default = "123")]
+ a: i32,
+}
+
+#[derive(AvroSchema)]
+enum B {
+ #[serde(rename = "A3")]
+ Item1,
+}
diff --git
a/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.expanded.rs
b/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.expanded.rs
new file mode 100644
index 0000000..d80a114
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.expanded.rs
@@ -0,0 +1,180 @@
+use apache_avro::AvroSchema;
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+struct A {
+ item: i32,
+ double_item: i32,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for A {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "A",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name A");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+ {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "ITEM".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "DOUBLE_ITEM".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ let schema_field_set: ::std::collections::HashSet<_> =
schema_fields
+ .iter()
+ .map(|rf| &rf.name)
+ .collect();
+ match (&schema_fields.len(), &schema_field_set.len()) {
+ (left_val, right_val) => {
+ if !(*left_val == *right_val) {
+ let kind = ::core::panicking::AssertKind::Eq;
+ ::core::panicking::assert_failed(
+ kind,
+ &*left_val,
+ &*right_val,
+ ::core::option::Option::Some(
+ format_args!(
+ "Duplicate field names found: {0:?}",
schema_fields,
+ ),
+ ),
+ );
+ }
+ }
+ };
+ let name = ::apache_avro::schema::Name::new("A")
+ .expect(
+ &::alloc::__export::must_use({
+ ::alloc::fmt::format(
+ format_args!(
+ "Unable to parse struct name for schema
{0}", "A",
+ ),
+ )
+ })[..],
+ );
+ let lookup: ::std::collections::BTreeMap<String, usize> =
schema_fields
+ .iter()
+ .enumerate()
+ .map(|(position, field)| (field.name.to_owned(), position))
+ .collect();
+
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ fields: schema_fields,
+ lookup,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ }
+ 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>> {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "ITEM".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "DOUBLE_ITEM".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ ::std::option::Option::Some(schema_fields)
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+enum B {
+ Item,
+ DoubleItem,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for B {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "B",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name B");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+
::apache_avro::schema::Schema::Enum(::apache_avro::schema::EnumSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ symbols: ::alloc::boxed::box_assume_init_into_vec_unsafe(
+ ::alloc::intrinsics::write_box_via_move(
+ ::alloc::boxed::Box::new_uninit(),
+ ["ITEM".to_owned(), "DOUBLE_ITEM".to_owned()],
+ ),
+ ),
+ default: ::std::option::Option::None,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ 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>> {
+ ::std::option::Option::None
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
diff --git a/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.rs
b/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.rs
new file mode 100644
index 0000000..6657f60
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_207_rename_all_attribute.rs
@@ -0,0 +1,32 @@
+// 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)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+struct A {
+ item: i32,
+ double_item: i32,
+}
+
+#[derive(AvroSchema)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+enum B {
+ Item,
+ DoubleItem,
+}
diff --git
a/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.expanded.rs
b/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.expanded.rs
new file mode 100644
index 0000000..0689cb1
--- /dev/null
+++
b/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.expanded.rs
@@ -0,0 +1,133 @@
+use apache_avro::AvroSchema;
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+struct A {
+ item: i32,
+ #[serde(rename = "DoubleItem")]
+ double_item: i32,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for A {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "A",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name A");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+ {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "ITEM".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "DoubleItem".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ let schema_field_set: ::std::collections::HashSet<_> =
schema_fields
+ .iter()
+ .map(|rf| &rf.name)
+ .collect();
+ match (&schema_fields.len(), &schema_field_set.len()) {
+ (left_val, right_val) => {
+ if !(*left_val == *right_val) {
+ let kind = ::core::panicking::AssertKind::Eq;
+ ::core::panicking::assert_failed(
+ kind,
+ &*left_val,
+ &*right_val,
+ ::core::option::Option::Some(
+ format_args!(
+ "Duplicate field names found: {0:?}",
schema_fields,
+ ),
+ ),
+ );
+ }
+ }
+ };
+ let name = ::apache_avro::schema::Name::new("A")
+ .expect(
+ &::alloc::__export::must_use({
+ ::alloc::fmt::format(
+ format_args!(
+ "Unable to parse struct name for schema
{0}", "A",
+ ),
+ )
+ })[..],
+ );
+ let lookup: ::std::collections::BTreeMap<String, usize> =
schema_fields
+ .iter()
+ .enumerate()
+ .map(|(position, field)| (field.name.to_owned(), position))
+ .collect();
+
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ fields: schema_fields,
+ lookup,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ }
+ 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>> {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "ITEM".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "DoubleItem".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ ::std::option::Option::Some(schema_fields)
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
diff --git
a/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.rs
b/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.rs
new file mode 100644
index 0000000..283b223
--- /dev/null
+++
b/avro_derive/tests/expanded/avro_rs_207_rename_attr_over_rename_all_attribute.rs
@@ -0,0 +1,26 @@
+// 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)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+struct A {
+ item: i32,
+ #[serde(rename = "DoubleItem")]
+ double_item: i32,
+}
diff --git a/avro_derive/tests/expanded/avro_rs_501_basic.expanded.rs
b/avro_derive/tests/expanded/avro_rs_501_basic.expanded.rs
new file mode 100644
index 0000000..34576a5
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_501_basic.expanded.rs
@@ -0,0 +1,180 @@
+use apache_avro::AvroSchema;
+struct A {
+ a: i32,
+ b: String,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for A {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "A",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name A");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+ {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "b".to_string(),
+ doc: ::std::option::Option::None,
+ default: <String as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <String as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ let schema_field_set: ::std::collections::HashSet<_> =
schema_fields
+ .iter()
+ .map(|rf| &rf.name)
+ .collect();
+ match (&schema_fields.len(), &schema_field_set.len()) {
+ (left_val, right_val) => {
+ if !(*left_val == *right_val) {
+ let kind = ::core::panicking::AssertKind::Eq;
+ ::core::panicking::assert_failed(
+ kind,
+ &*left_val,
+ &*right_val,
+ ::core::option::Option::Some(
+ format_args!(
+ "Duplicate field names found: {0:?}",
schema_fields,
+ ),
+ ),
+ );
+ }
+ }
+ };
+ let name = ::apache_avro::schema::Name::new("A")
+ .expect(
+ &::alloc::__export::must_use({
+ ::alloc::fmt::format(
+ format_args!(
+ "Unable to parse struct name for schema
{0}", "A",
+ ),
+ )
+ })[..],
+ );
+ let lookup: ::std::collections::BTreeMap<String, usize> =
schema_fields
+ .iter()
+ .enumerate()
+ .map(|(position, field)| (field.name.to_owned(), position))
+ .collect();
+
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ fields: schema_fields,
+ lookup,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ }
+ 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>> {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "b".to_string(),
+ doc: ::std::option::Option::None,
+ default: <String as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <String as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ ::std::option::Option::Some(schema_fields)
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
+enum Basic {
+ A,
+ B,
+ C,
+ D,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for Basic {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "Basic",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name Basic");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+
::apache_avro::schema::Schema::Enum(::apache_avro::schema::EnumSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ symbols: ::alloc::boxed::box_assume_init_into_vec_unsafe(
+ ::alloc::intrinsics::write_box_via_move(
+ ::alloc::boxed::Box::new_uninit(),
+ ["A".to_owned(), "B".to_owned(), "C".to_owned(),
"D".to_owned()],
+ ),
+ ),
+ default: ::std::option::Option::None,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ 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>> {
+ ::std::option::Option::None
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
diff --git a/avro_derive/tests/expanded/avro_rs_501_basic.rs
b/avro_derive/tests/expanded/avro_rs_501_basic.rs
new file mode 100644
index 0000000..ea90024
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_501_basic.rs
@@ -0,0 +1,32 @@
+// 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 A {
+ a: i32,
+ b: String,
+}
+
+#[derive(AvroSchema)]
+enum Basic {
+ A,
+ B,
+ C,
+ D,
+}
diff --git a/avro_derive/tests/expanded/avro_rs_501_namespace.expanded.rs
b/avro_derive/tests/expanded/avro_rs_501_namespace.expanded.rs
new file mode 100644
index 0000000..ce84a5d
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_501_namespace.expanded.rs
@@ -0,0 +1,133 @@
+use apache_avro::AvroSchema;
+#[avro(namespace = "namespace.testing")]
+struct A {
+ a: i32,
+ b: String,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for A {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "namespace.testing.A",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name namespace.testing.A");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+ {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "b".to_string(),
+ doc: ::std::option::Option::None,
+ default: <String as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <String as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ let schema_field_set: ::std::collections::HashSet<_> =
schema_fields
+ .iter()
+ .map(|rf| &rf.name)
+ .collect();
+ match (&schema_fields.len(), &schema_field_set.len()) {
+ (left_val, right_val) => {
+ if !(*left_val == *right_val) {
+ let kind = ::core::panicking::AssertKind::Eq;
+ ::core::panicking::assert_failed(
+ kind,
+ &*left_val,
+ &*right_val,
+ ::core::option::Option::Some(
+ format_args!(
+ "Duplicate field names found: {0:?}",
schema_fields,
+ ),
+ ),
+ );
+ }
+ }
+ };
+ let name =
::apache_avro::schema::Name::new("namespace.testing.A")
+ .expect(
+ &::alloc::__export::must_use({
+ ::alloc::fmt::format(
+ format_args!(
+ "Unable to parse struct name for schema
{0}",
+ "namespace.testing.A",
+ ),
+ )
+ })[..],
+ );
+ let lookup: ::std::collections::BTreeMap<String, usize> =
schema_fields
+ .iter()
+ .enumerate()
+ .map(|(position, field)| (field.name.to_owned(), position))
+ .collect();
+
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ fields: schema_fields,
+ lookup,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ }
+ 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>> {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a".to_string(),
+ doc: ::std::option::Option::None,
+ default: <i32 as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <i32 as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "b".to_string(),
+ doc: ::std::option::Option::None,
+ default: <String as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <String as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ ::std::option::Option::Some(schema_fields)
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
diff --git a/avro_derive/tests/expanded/avro_rs_501_namespace.rs
b/avro_derive/tests/expanded/avro_rs_501_namespace.rs
new file mode 100644
index 0000000..ea7c89f
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_501_namespace.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)]
+#[avro(namespace = "namespace.testing")]
+struct A {
+ a: i32,
+ b: String,
+}
diff --git a/avro_derive/tests/expanded/avro_rs_501_reference.expanded.rs
b/avro_derive/tests/expanded/avro_rs_501_reference.expanded.rs
new file mode 100644
index 0000000..9916d4f
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_501_reference.expanded.rs
@@ -0,0 +1,139 @@
+use apache_avro::AvroSchema;
+struct A<'a> {
+ a: &'a Vec<i32>,
+ b: &'static str,
+}
+#[automatically_derived]
+impl<'a> ::apache_avro::AvroSchemaComponent for A<'a> {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "A",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name A");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+ {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a".to_string(),
+ doc: ::std::option::Option::None,
+ default: <&'a Vec<
+ i32,
+ > as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <&'a Vec<
+ i32,
+ > as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "b".to_string(),
+ doc: ::std::option::Option::None,
+ default: <&'static str as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <&'static str as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ let schema_field_set: ::std::collections::HashSet<_> =
schema_fields
+ .iter()
+ .map(|rf| &rf.name)
+ .collect();
+ match (&schema_fields.len(), &schema_field_set.len()) {
+ (left_val, right_val) => {
+ if !(*left_val == *right_val) {
+ let kind = ::core::panicking::AssertKind::Eq;
+ ::core::panicking::assert_failed(
+ kind,
+ &*left_val,
+ &*right_val,
+ ::core::option::Option::Some(
+ format_args!(
+ "Duplicate field names found: {0:?}",
schema_fields,
+ ),
+ ),
+ );
+ }
+ }
+ };
+ let name = ::apache_avro::schema::Name::new("A")
+ .expect(
+ &::alloc::__export::must_use({
+ ::alloc::fmt::format(
+ format_args!(
+ "Unable to parse struct name for schema
{0}", "A",
+ ),
+ )
+ })[..],
+ );
+ let lookup: ::std::collections::BTreeMap<String, usize> =
schema_fields
+ .iter()
+ .enumerate()
+ .map(|(position, field)| (field.name.to_owned(), position))
+ .collect();
+
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ fields: schema_fields,
+ lookup,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ }
+ 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>> {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(2usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a".to_string(),
+ doc: ::std::option::Option::None,
+ default: <&'a Vec<
+ i32,
+ > as ::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <&'a Vec<
+ i32,
+ > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "b".to_string(),
+ doc: ::std::option::Option::None,
+ default: <&'static str as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <&'static str as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ ::std::option::Option::Some(schema_fields)
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
diff --git a/avro_derive/tests/expanded/avro_rs_501_reference.rs
b/avro_derive/tests/expanded/avro_rs_501_reference.rs
new file mode 100644
index 0000000..af8b4e2
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_501_reference.rs
@@ -0,0 +1,24 @@
+// 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 A<'a> {
+ a: &'a Vec<i32>,
+ b: &'static str,
+}
diff --git
a/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.expanded.rs
b/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.expanded.rs
new file mode 100644
index 0000000..076143e
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.expanded.rs
@@ -0,0 +1,115 @@
+use apache_avro::AvroSchema;
+struct TestOptional {
+ a: Option<i32>,
+}
+#[automatically_derived]
+impl ::apache_avro::AvroSchemaComponent for TestOptional {
+ 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 {
+ let name = ::apache_avro::schema::Name::new_with_enclosing_namespace(
+ "TestOptional",
+ enclosing_namespace,
+ )
+ .expect("Unable to parse schema name TestOptional");
+ if named_schemas.contains(&name) {
+ ::apache_avro::schema::Schema::Ref {
+ name,
+ }
+ } else {
+ let enclosing_namespace = name.namespace();
+ named_schemas.insert(name.clone());
+ {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(1usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a".to_string(),
+ doc: ::std::option::Option::None,
+ default: <Option<
+ i32,
+ > as
::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <Option<
+ i32,
+ > as
::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ let schema_field_set: ::std::collections::HashSet<_> =
schema_fields
+ .iter()
+ .map(|rf| &rf.name)
+ .collect();
+ match (&schema_fields.len(), &schema_field_set.len()) {
+ (left_val, right_val) => {
+ if !(*left_val == *right_val) {
+ let kind = ::core::panicking::AssertKind::Eq;
+ ::core::panicking::assert_failed(
+ kind,
+ &*left_val,
+ &*right_val,
+ ::core::option::Option::Some(
+ format_args!(
+ "Duplicate field names found: {0:?}",
schema_fields,
+ ),
+ ),
+ );
+ }
+ }
+ };
+ let name = ::apache_avro::schema::Name::new("TestOptional")
+ .expect(
+ &::alloc::__export::must_use({
+ ::alloc::fmt::format(
+ format_args!(
+ "Unable to parse struct name for schema
{0}",
+ "TestOptional",
+ ),
+ )
+ })[..],
+ );
+ let lookup: ::std::collections::BTreeMap<String, usize> =
schema_fields
+ .iter()
+ .enumerate()
+ .map(|(position, field)| (field.name.to_owned(), position))
+ .collect();
+
::apache_avro::schema::Schema::Record(::apache_avro::schema::RecordSchema {
+ name,
+ aliases: ::std::option::Option::None,
+ doc: ::std::option::Option::None,
+ fields: schema_fields,
+ lookup,
+ attributes: ::std::collections::BTreeMap::new(),
+ })
+ }
+ }
+ }
+ 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>> {
+ let mut schema_fields = ::std::vec::Vec::with_capacity(1usize);
+ schema_fields
+ .push(::apache_avro::schema::RecordField {
+ name: "a".to_string(),
+ doc: ::std::option::Option::None,
+ default: <Option<
+ i32,
+ > as ::apache_avro::AvroSchemaComponent>::field_default(),
+ aliases: ::std::vec::Vec::new(),
+ schema: <Option<
+ i32,
+ > as ::apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(
+ named_schemas,
+ enclosing_namespace,
+ ),
+ custom_attributes: ::std::collections::BTreeMap::new(),
+ });
+ ::std::option::Option::Some(schema_fields)
+ }
+ fn field_default() -> ::std::option::Option<::serde_json::Value> {
+ ::std::option::Option::None
+ }
+}
diff --git a/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.rs
b/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.rs
new file mode 100644
index 0000000..5b9a63f
--- /dev/null
+++ b/avro_derive/tests/expanded/avro_rs_501_struct_with_optional.rs
@@ -0,0 +1,23 @@
+// 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 TestOptional {
+ a: Option<i32>,
+}
diff --git a/avro_derive/tests/expanded/mod.rs
b/avro_derive/tests/expanded/mod.rs
new file mode 100644
index 0000000..adaa76a
--- /dev/null
+++ b/avro_derive/tests/expanded/mod.rs
@@ -0,0 +1,29 @@
+// 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.
+
+#![expect(dead_code, reason = "Only code generation is tested")]
+
+// Do not include the `.expanded` modules here, as that code won't compile
+
+mod avro_3687_basic_enum_with_default;
+mod avro_3709_record_field_attributes;
+mod avro_rs_207_rename_all_attribute;
+mod avro_rs_207_rename_attr_over_rename_all_attribute;
+mod avro_rs_501_basic;
+mod avro_rs_501_namespace;
+mod avro_rs_501_reference;
+mod avro_rs_501_struct_with_optional;
diff --git a/avro_derive/tests/ui/avro_3687_basic_enum_with_default_twice.rs
b/avro_derive/tests/ui/avro_3687_basic_enum_with_default_twice.rs
new file mode 100644
index 0000000..2ba3e44
--- /dev/null
+++ b/avro_derive/tests/ui/avro_3687_basic_enum_with_default_twice.rs
@@ -0,0 +1,30 @@
+// 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, Default)]
+enum Basic {
+ #[default]
+ A,
+ B,
+ #[default]
+ C,
+ D
+}
+
+fn main() {}
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
new file mode 100644
index 0000000..14a3798
--- /dev/null
+++ b/avro_derive/tests/ui/avro_3687_basic_enum_with_default_twice.stderr
@@ -0,0 +1,19 @@
+error: Multiple defaults defined: ["A", "C"]
+ --> tests/ui/avro_3687_basic_enum_with_default_twice.rs:21:6
+ |
+21 | enum Basic {
+ | ^^^^^
+
+error: multiple declared defaults
+ --> tests/ui/avro_3687_basic_enum_with_default_twice.rs:20:22
+ |
+20 | #[derive(AvroSchema, Default)]
+ | ^^^^^^^
+...
+23 | A,
+ | - first default
+...
+26 | C,
+ | - additional default
+ |
+ = note: only one variant can be default
diff --git a/avro_derive/tests/ui/avro_rs_501_non_basic_enum.rs
b/avro_derive/tests/ui/avro_rs_501_non_basic_enum.rs
new file mode 100644
index 0000000..72230d8
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_501_non_basic_enum.rs
@@ -0,0 +1,28 @@
+// 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)]
+enum NonBasic {
+ A(i32),
+ B,
+ C,
+ D
+}
+
+fn main() {}
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
new file mode 100644
index 0000000..961253b
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_501_non_basic_enum.stderr
@@ -0,0 +1,5 @@
+error: AvroSchema: derive does not work for enums with non unit structs
+ --> tests/ui/avro_rs_501_non_basic_enum.rs:21:6
+ |
+21 | enum NonBasic {
+ | ^^^^^^^^
diff --git a/avro_derive/tests/ui/avro_rs_501_tuple_struct.rs
b/avro_derive/tests/ui/avro_rs_501_tuple_struct.rs
new file mode 100644
index 0000000..1e64845
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_501_tuple_struct.rs
@@ -0,0 +1,23 @@
+// 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 B(i32, String);
+
+fn main() {}
diff --git a/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr
b/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr
new file mode 100644
index 0000000..1091ec0
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_501_tuple_struct.stderr
@@ -0,0 +1,5 @@
+error: AvroSchema derive does not work for tuple structs
+ --> tests/ui/avro_rs_501_tuple_struct.rs:21:8
+ |
+21 | struct B(i32, String);
+ | ^
diff --git a/avro_derive/tests/ui/avro_rs_501_unit_struct.rs
b/avro_derive/tests/ui/avro_rs_501_unit_struct.rs
new file mode 100644
index 0000000..1b740af
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_501_unit_struct.rs
@@ -0,0 +1,23 @@
+// 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 AbsoluteUnit;
+
+fn main() {}
diff --git a/avro_derive/tests/ui/avro_rs_501_unit_struct.stderr
b/avro_derive/tests/ui/avro_rs_501_unit_struct.stderr
new file mode 100644
index 0000000..2a16ef6
--- /dev/null
+++ b/avro_derive/tests/ui/avro_rs_501_unit_struct.stderr
@@ -0,0 +1,5 @@
+error: AvroSchema derive does not work for unit structs
+ --> tests/ui/avro_rs_501_unit_struct.rs:21:8
+ |
+21 | struct AbsoluteUnit;
+ | ^^^^^^^^^^^^
diff --git a/licenserc.toml b/licenserc.toml
index 2c153a7..7ef9fe6 100644
--- a/licenserc.toml
+++ b/licenserc.toml
@@ -18,6 +18,7 @@
headerPath = "Apache-2.0-ASF.txt"
excludes = [
"*.stderr",
+ "*.expanded.rs",
"*.avro",
"NOTICE",
"README.tpl",