Skip to content

Conversation

@Kriskras99
Copy link
Contributor

This commit changes the attribute parsing in #[derive(AvroSchema)] to also use the Serde attributes. It will use the Serde attributes and check that they match the Avro attributes if provided. It will also check that known incompatible Serde attributes result in a compile error instead of a runtime panic.

Testing for the compile errors is done using trybuild. These tests run only on nightly as the output can vary between compiler versions (otherwise MSRV and latest stable could have different outputs and break the entire CI).

For some reason Github closed #373, not sure why. This is the exact same commit.

if avro.skip && !serde.skip {
errors.push(syn::Error::new(
span,
"`#[avro(skip)]` requires `#[serde(skip)]`, it's also deprecated. Please use only `#[serde(skip)]`"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to report the usage of a deprecated avro(attribute) as a warning without depending on the value of its respective serde counter-part ?
I.e. pseudo code:

if avro.skip { report a warning like "#[avro(skip)] is deprecated. Use #[serde(skip)] instead" }

if avro.skip != serde.skip {report an error, without the ", it's also deprecated" text}

Currently the user will be notified that a deprecated avro attribute is used only if the avro value differs from the serde's one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's only possible on nightly sadly (rust-lang/rust#54140). We could put #[rustversion::attr(not(nightly), ignore)] on a codeblock and only emit warnings on nightly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good!
Let's do it!
Then once it is in stable and our MSRV is at least this stable version we could delete just this attribute to enable it for all.

@Kriskras99 Kriskras99 force-pushed the feat/use_serde_attributes2 branch from 762c230 to 4efa998 Compare December 28, 2025 14:35
This commit changes the attribute parsing in `#[derive(AvroSchema)]` to also use the Serde attributes.
It will use the Serde attributes and check that they match the Avro attributes if provided. It will
also check that known incompatible Serde attributes result in a compile error instead of a runtime panic.

Testing for the compile errors is done using `trybuild`. These tests run only on nightly as the output
can vary between compiler versions (otherwise MSRV and latest stable could have different outputs and break the entire CI).
@Kriskras99 Kriskras99 force-pushed the feat/use_serde_attributes2 branch from 4efa998 to 392ae2c Compare December 28, 2025 14:40
@martin-g
Copy link
Member

A PR has been opened at Derling repo with an example how to parse serde:
https://github.com/TedDriggs/darling/pull/412/changes#diff-9df22bcc91f2a6d5114da4fff9f20353fb0171013e7a7fa385cea38e6130f691

We may borrow something useful from it.

}
pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
match rename_all_str {
"lowercase" => Ok(Self::LowerCase),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this no more uses RENAME_RULES ? Now the rules are duplicated.

          RENAME_RULES
            .iter()
            .find(|(name, _)| *name == rename_all_str)
            .map(|(_, rule)| *rule)
            .ok_or_else(|| ParseError {
                unknown: rename_all_str.to_string(),
            })

impl RenameAll {
fn from_expr(expr: &Expr) -> darling::Result<Self> {
let Expr::Lit(lit) = expr else {
return Err(darling::Error::custom("Expected a string or a tuple!"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return Err(darling::Error::custom("Expected a string or a tuple!"));
return Err(darling::Error::custom("Expected a string literal!"));

The tuple form is handled by FromMeta derive.

if avro.skip && !serde.skip {
errors.push(syn::Error::new(
span,
"`#[avro(skip)]` requires `#[serde(skip)]`, it's also deprecated. Please use only `#[serde(skip)]`"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good!
Let's do it!
Then once it is in stable and our MSRV is at least this stable version we could delete just this attribute to enable it for all.

if avro.rename.is_some() && serde.rename != avro.rename {
errors.push(syn::Error::new(
span,
"`#[avro(rename = \"..\")]` must match `#[serde(rename = \"..\")]`, it's also deprecated. Please use only `#[serde(rename = \"..\")]`"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"`#[avro(rename = \"..\")]` must match `#[serde(rename = \"..\")]`, it's also deprecated. Please use only `#[serde(rename = \"..\")]`"
"`#[avro(rename = \"..\")]` must match `#[serde(rename = \"..\")]`, it's also deprecated. Please use only `#[serde(rename = \"..\")]`"

if avro.rename.is_some() && serde.rename != avro.rename {
errors.push(syn::Error::new(
span,
"`#[avro(rename = \"..\")]` must match `#[serde(rename = \"..\")]`, it's also deprecated. Please use only `#[serde(rename = \"..\")]`"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"`#[avro(rename = \"..\")]` must match `#[serde(rename = \"..\")]`, it's also deprecated. Please use only `#[serde(rename = \"..\")]`"
"`#[avro(rename = \"..\")]` must match `#[serde(rename = \"..\")]`, it's also deprecated. Please use only `#[serde(rename = \"..\")]`"

assert_eq!(obj, serde(obj.clone()).unwrap());
}

/// Takes in a type that implements the right combination of traits and runs it through a Serde Cycle and asserts that the error matches the expected string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Takes in a type that implements the right combination of traits and runs it through a Serde Cycle and asserts that the error matches the expected string
/// Takes in a type that implements the right combination of traits and runs it through a Serde round-trip and asserts that the error matches the expected string

if let Some(res) = reader.next() {
return res.and_then(|v| from_value::<T>(&v));
}
unreachable!("Nothing was encoded!")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unreachable!("Nothing was encoded!")
panic!("Nothing was encoded!")

let schema = r#"
{
"type":"record",
"name":"Foo",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be "Bar" ?!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"name":"bar",
"type": {
"type":"record",
"name":"Foo",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bar ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub struct ContainerAttributes {
#[darling(rename = "rename")]
/// Rename this container.
pub _rename: Option<String>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed in tests/serde.rs that this attribute is ignored.
Shall we try to support it too ?

  1. if #[avro(name=...)] is provided then use it
  2. if #[serde(rename=...)] is provided then use it
  3. if both are provided then error
  4. if none are provided then use the struct name

WDYT ?

errors.push(syn::Error::new(
span,
"AvroSchema derive does not support Serde `transparent` attribute",
))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
))
));

errors.push(syn::Error::new(
span,
"AvroSchema derive does not support different rename rules for serializing and deserializing (`rename_all(serialize = \"..\", deserialize = \"..\")`)"
))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
))
));

errors.push(syn::Error::new(
span,
"#[avro(rename_all = \"..\")] must match #[serde(rename_all = \"..\")], it's also deprecated. Please use only `#[serde(rename_all = \"..\")]`",
))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
))
));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants