This is an automated email from the ASF dual-hosted git repository.
Kriskras99 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 7349015 fix: Enable `#[serde(remote = "..")]` support (#564)
7349015 is described below
commit 7349015a402a502c9cfa2d323c2273bbd3680ab1
Author: Kriskras99 <[email protected]>
AuthorDate: Tue Jun 23 21:04:38 2026 +0200
fix: Enable `#[serde(remote = "..")]` support (#564)
* fix: Enable `#[serde(remote = "..")]` support
* fix: Improve documentation and fix test name
---
avro/src/serde/derive.rs | 3 --
avro_derive/src/attributes/mod.rs | 14 ------
avro_derive/src/attributes/serde.rs | 11 +++--
avro_derive/tests/serde.rs | 68 ++++++++++++++++++++++++++
avro_derive/tests/ui/avro_rs_373_remote.rs | 33 -------------
avro_derive/tests/ui/avro_rs_373_remote.stderr | 9 ----
6 files changed, 76 insertions(+), 62 deletions(-)
diff --git a/avro/src/serde/derive.rs b/avro/src/serde/derive.rs
index 38f17bf..6d66fce 100644
--- a/avro/src/serde/derive.rs
+++ b/avro/src/serde/derive.rs
@@ -175,13 +175,10 @@ use crate::{
/// - `untagged`
/// - `variant_identifier`
/// - `field_identifier`
-/// - `remote`
/// - `rename_all(serialize = "..", deserialize = "..")` where `serialize`
!= `deserialize`
/// - Variant attributes
/// - `other`
/// - `untagged`
-/// - Field attributes
-/// - `getter`
///
/// ## Working with foreign types
///
diff --git a/avro_derive/src/attributes/mod.rs
b/avro_derive/src/attributes/mod.rs
index ebb2997..e68bbbb 100644
--- a/avro_derive/src/attributes/mod.rs
+++ b/avro_derive/src/attributes/mod.rs
@@ -63,12 +63,6 @@ impl NamedTypeOptions {
"AvroSchema derive does not support changing the tagging Serde
generates (`tag`, `content`, `untagged`, `variant_identifier`,
`field_identifier`)",
));
}
- if serde.remote.is_some() {
- errors.push(syn::Error::new(
- span,
- "AvroSchema derive does not support the Serde `remote`
attribute",
- ));
- }
if serde.rename_all.deserialize != serde.rename_all.serialize {
errors.push(syn::Error::new(
span,
@@ -284,14 +278,6 @@ impl FieldOptions {
// Collect errors so user gets all feedback at once
let mut errors = Vec::new();
- // Check for any Serde attributes that are hard errors
- if serde.getter.is_some() {
- errors.push(syn::Error::new(
- span,
- "AvroSchema derive does not support the Serde `getter`
attribute",
- ));
- }
-
// Check for conflicts between Serde and Avro
if avro.skip && !(serde.skip || (serde.skip_serializing &&
serde.skip_deserializing)) {
errors.push(syn::Error::new(
diff --git a/avro_derive/src/attributes/serde.rs
b/avro_derive/src/attributes/serde.rs
index b1ca6fa..6149752 100644
--- a/avro_derive/src/attributes/serde.rs
+++ b/avro_derive/src/attributes/serde.rs
@@ -117,8 +117,12 @@ pub struct ContainerAttributes {
pub _default: Option<SerdeDefault>,
/// This type is the serde implementation for a "remote" type.
///
- /// This makes the (de)serialisation use/return a different type.
- pub remote: Option<String>,
+ /// This allows the user to derive `Serialize`/`Deserialize` for a type in
another crate.
+ ///
+ /// This makes the (de)serialisation use/return a different type. To make
this work Serde requires
+ /// that the remote type and this type have the same fields so the schema
generated is correct.
+ #[darling(rename = "remote")]
+ pub _remote: Option<String>,
/// Directly use the inner type for (de)serialisation.
#[darling(default)]
pub transparent: bool,
@@ -243,7 +247,8 @@ pub struct FieldAttributes {
#[darling(rename = "borrow")]
pub _borrow: Option<SerdeBorrow>,
/// Used for remote types.
- pub getter: Option<String>,
+ #[darling(rename = "getter")]
+ pub _getter: Option<String>,
}
#[cfg(test)]
diff --git a/avro_derive/tests/serde.rs b/avro_derive/tests/serde.rs
index 128fede..0f03713 100644
--- a/avro_derive/tests/serde.rs
+++ b/avro_derive/tests/serde.rs
@@ -370,6 +370,74 @@ mod container_attributes {
a: vec!["spam".to_string()],
});
}
+
+ #[test]
+ fn avro_rs_564_remote() {
+ // The types and supporting code here have been pulled directly from
the Serde documentation
+ // (https://serde.rs/remote-derive.html)
+
+ // Pretend that this is somebody else's crate, not a module.
+ mod other_crate {
+ // Neither Serde nor the other crate provides Serialize and
Deserialize
+ // impls for this struct. Oh, and the fields are private.
+ #[derive(Debug, PartialEq, Eq)]
+ pub struct Duration {
+ secs: i64,
+ nanos: i32,
+ }
+
+ impl Duration {
+ pub fn new(secs: i64, nanos: i32) -> Self {
+ Duration { secs, nanos }
+ }
+
+ pub fn seconds(&self) -> i64 {
+ self.secs
+ }
+
+ pub fn subsec_nanos(&self) -> i32 {
+ self.nanos
+ }
+ }
+ }
+
+
////////////////////////////////////////////////////////////////////////////////
+
+ use other_crate::Duration;
+ use serde::{Deserialize, Serialize};
+
+ // Provide getters for every private field of the remote struct. The
getter must
+ // return either `T` or `&T` where `T` is the type of the field.
+ #[derive(Serialize, Deserialize, AvroSchema)]
+ #[serde(remote = "Duration")]
+ struct DurationDef {
+ #[serde(getter = "Duration::seconds")]
+ secs: i64,
+ #[serde(getter = "Duration::subsec_nanos")]
+ nanos: i32,
+ }
+
+ // Provide a conversion to construct the remote type.
+ impl From<DurationDef> for Duration {
+ fn from(def: DurationDef) -> Duration {
+ Duration::new(def.secs, def.nanos)
+ }
+ }
+
+ #[derive(Serialize, Deserialize, AvroSchema, Debug, PartialEq, Eq)]
+ struct Process {
+ command_line: String,
+
+ #[serde(with = "DurationDef")]
+ #[avro(with)]
+ wall_time: Duration,
+ }
+
+ serde_assert(Process {
+ command_line: "abracadabra".to_string(),
+ wall_time: Duration::new(15, 42),
+ });
+ }
}
mod variant_attributes {
diff --git a/avro_derive/tests/ui/avro_rs_373_remote.rs
b/avro_derive/tests/ui/avro_rs_373_remote.rs
deleted file mode 100644
index b6029c8..0000000
--- a/avro_derive/tests/ui/avro_rs_373_remote.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-use apache_avro::AvroSchema;
-
-#[derive(AvroSchema)]
-struct Foo {
- a: String,
- b: i32,
-}
-
-#[derive(AvroSchema)]
-#[serde(remote = "Foo")]
-struct FooRemote {
- a: String,
- b: i32,
-}
-
-pub fn main() {}
diff --git a/avro_derive/tests/ui/avro_rs_373_remote.stderr
b/avro_derive/tests/ui/avro_rs_373_remote.stderr
deleted file mode 100644
index fe4fd10..0000000
--- a/avro_derive/tests/ui/avro_rs_373_remote.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error: AvroSchema derive does not support the Serde `remote` attribute
- --> tests/ui/avro_rs_373_remote.rs:27:1
- |
-27 | / #[serde(remote = "Foo")]
-28 | | struct FooRemote {
-29 | | a: String,
-30 | | b: i32,
-31 | | }
- | |_^