You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by mg...@apache.org on 2026/01/08 04:03:46 UTC
(avro-rs) 01/01: feat!:Make AvroSchemaComponent available without `derive` feature
This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch 363-make-AvroSchemaComponent-always-available
in repository https://gitbox.apache.org/repos/asf/avro-rs.git
commit f4636168f183115ce2c0d0cd6d6d931d42a6a0a4
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
AuthorDate: Thu Jan 8 06:02:27 2026 +0200
feat!:Make AvroSchemaComponent available without `derive` feature
Fixes #363
Signed-off-by: Martin Tzvetanov Grigorov <mg...@apache.org>
---
avro/src/lib.rs | 2 +-
avro/src/schema.rs | 105 ++++++++++++++++++++++----------------------
avro_derive/src/lib.rs | 16 +++----
avro_derive/tests/derive.rs | 2 +-
4 files changed, 62 insertions(+), 63 deletions(-)
diff --git a/avro/src/lib.rs b/avro/src/lib.rs
index 5c744ff..bfeb6bf 100644
--- a/avro/src/lib.rs
+++ b/avro/src/lib.rs
@@ -984,7 +984,7 @@ pub use reader::{
GenericSingleObjectReader, Reader, SpecificSingleObjectReader, from_avro_datum,
from_avro_datum_reader_schemata, from_avro_datum_schemata, read_marker,
};
-pub use schema::{AvroSchema, Schema};
+pub use schema::{AvroSchema, AvroSchemaComponent, Schema};
pub use serde::{de::from_value, ser::to_value};
pub use uuid::Uuid;
pub use writer::{
diff --git a/avro/src/schema.rs b/avro/src/schema.rs
index 9d988c8..be728f3 100644
--- a/avro/src/schema.rs
+++ b/avro/src/schema.rs
@@ -2574,64 +2574,63 @@ pub trait AvroSchema {
fn get_schema() -> Schema;
}
+/// Trait for types that serve as fully defined components inside an Avro data model. Derive
+/// implementation available through `derive` feature. This is what is implemented by
+/// the `derive(AvroSchema)` macro.
+///
+/// # Implementation guide
+///
+///### Simple implementation
+/// To construct a non named simple schema, it is possible to ignore the input argument making the
+/// general form implementation look like
+/// ```ignore
+/// impl AvroSchemaComponent for AType {
+/// fn get_schema_in_ctxt(_: &mut Names, _: &Namespace) -> Schema {
+/// Schema::?
+/// }
+///}
+/// ```
+/// ### Passthrough implementation
+/// To construct a schema for a Type that acts as in "inner" type, such as for smart pointers, simply
+/// pass through the arguments to the inner type
+/// ```ignore
+/// impl AvroSchemaComponent for PassthroughType {
+/// fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: &Namespace) -> Schema {
+/// InnerType::get_schema_in_ctxt(names, enclosing_namespace)
+/// }
+///}
+/// ```
+///### Complex implementation
+/// To implement this for Named schema there is a general form needed to avoid creating invalid
+/// schemas or infinite loops.
+/// ```ignore
+/// impl AvroSchemaComponent for ComplexType {
+/// fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: &Namespace) -> Schema {
+/// // Create the fully qualified name for your type given the enclosing namespace
+/// let name = apache_avro::schema::Name::new("MyName")
+/// .expect("Unable to parse schema name")
+/// .fully_qualified_name(enclosing_namespace);
+/// let enclosing_namespace = &name.namespace;
+/// // Check, if your name is already defined, and if so, return a ref to that name
+/// if named_schemas.contains_key(&name) {
+/// apache_avro::schema::Schema::Ref{name: name.clone()}
+/// } else {
+/// named_schemas.insert(name.clone(), apache_avro::schema::Schema::Ref{name: name.clone()});
+/// // YOUR SCHEMA DEFINITION HERE with the name equivalent to "MyName".
+/// // For non-simple sub types delegate to their implementation of AvroSchemaComponent
+/// }
+/// }
+///}
+/// ```
+pub trait AvroSchemaComponent {
+ fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: &Namespace) -> Schema;
+}
+
#[cfg(feature = "derive")]
pub mod derive {
use super::*;
use std::borrow::Cow;
- /// Trait for types that serve as fully defined components inside an Avro data model. Derive
- /// implementation available through `derive` feature. This is what is implemented by
- /// the `derive(AvroSchema)` macro.
- ///
- /// # Implementation guide
- ///
- ///### Simple implementation
- /// To construct a non named simple schema, it is possible to ignore the input argument making the
- /// general form implementation look like
- /// ```ignore
- /// impl AvroSchemaComponent for AType {
- /// fn get_schema_in_ctxt(_: &mut Names, _: &Namespace) -> Schema {
- /// Schema::?
- /// }
- ///}
- /// ```
- /// ### Passthrough implementation
- /// To construct a schema for a Type that acts as in "inner" type, such as for smart pointers, simply
- /// pass through the arguments to the inner type
- /// ```ignore
- /// impl AvroSchemaComponent for PassthroughType {
- /// fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: &Namespace) -> Schema {
- /// InnerType::get_schema_in_ctxt(names, enclosing_namespace)
- /// }
- ///}
- /// ```
- ///### Complex implementation
- /// To implement this for Named schema there is a general form needed to avoid creating invalid
- /// schemas or infinite loops.
- /// ```ignore
- /// impl AvroSchemaComponent for ComplexType {
- /// fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: &Namespace) -> Schema {
- /// // Create the fully qualified name for your type given the enclosing namespace
- /// let name = apache_avro::schema::Name::new("MyName")
- /// .expect("Unable to parse schema name")
- /// .fully_qualified_name(enclosing_namespace);
- /// let enclosing_namespace = &name.namespace;
- /// // Check, if your name is already defined, and if so, return a ref to that name
- /// if named_schemas.contains_key(&name) {
- /// apache_avro::schema::Schema::Ref{name: name.clone()}
- /// } else {
- /// named_schemas.insert(name.clone(), apache_avro::schema::Schema::Ref{name: name.clone()});
- /// // YOUR SCHEMA DEFINITION HERE with the name equivalent to "MyName".
- /// // For non-simple sub types delegate to their implementation of AvroSchemaComponent
- /// }
- /// }
- ///}
- /// ```
- pub trait AvroSchemaComponent {
- fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: &Namespace)
- -> Schema;
- }
-
impl<T> AvroSchema for T
where
T: AvroSchemaComponent,
diff --git a/avro_derive/src/lib.rs b/avro_derive/src/lib.rs
index 8723593..c3587ed 100644
--- a/avro_derive/src/lib.rs
+++ b/avro_derive/src/lib.rs
@@ -84,7 +84,7 @@ fn derive_avro_schema(input: &mut DeriveInput) -> Result<TokenStream, Vec<syn::E
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
Ok(quote! {
#[automatically_derived]
- impl #impl_generics apache_avro::schema::derive::AvroSchemaComponent for #ident #ty_generics #where_clause {
+ impl #impl_generics apache_avro::AvroSchemaComponent for #ident #ty_generics #where_clause {
fn get_schema_in_ctxt(named_schemas: &mut std::collections::HashMap<apache_avro::schema::Name, apache_avro::schema::Schema>, enclosing_namespace: &Option<String>) -> apache_avro::schema::Schema {
let name = apache_avro::schema::Name::new(#full_schema_name).expect(&format!("Unable to parse schema name {}", #full_schema_name)[..]).fully_qualified_name(enclosing_namespace);
let enclosing_namespace = &name.namespace;
@@ -338,10 +338,10 @@ fn is_default_attr(attr: &Attribute) -> bool {
}
/// Generates the schema def expression for fully qualified type paths using the associated function
-/// - `A -> <A as apache_avro::schema::derive::AvroSchemaComponent>::get_schema_in_ctxt()`
-/// - `A<T> -> <A<T> as apache_avro::schema::derive::AvroSchemaComponent>::get_schema_in_ctxt()`
+/// - `A -> <A as apache_avro::AvroSchemaComponent>::get_schema_in_ctxt()`
+/// - `A<T> -> <A<T> as apache_avro::AvroSchemaComponent>::get_schema_in_ctxt()`
fn type_path_schema_expr(p: &TypePath) -> TokenStream {
- quote! {<#p as apache_avro::schema::derive::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, enclosing_namespace)}
+ quote! {<#p as apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, enclosing_namespace)}
}
/// Stolen from serde
@@ -496,7 +496,7 @@ mod tests {
assert!(derived.is_ok());
assert_eq!(derived.unwrap().to_string(), quote! {
#[automatically_derived]
- impl apache_avro::schema::derive::AvroSchemaComponent for Basic {
+ impl apache_avro::AvroSchemaComponent for Basic {
fn get_schema_in_ctxt(
named_schemas: &mut std::collections::HashMap<
apache_avro::schema::Name,
@@ -640,9 +640,9 @@ mod tests {
#[test]
fn test_trait_cast() {
- assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{i32}).unwrap()).to_string(), quote!{<i32 as apache_avro::schema::derive::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, enclosing_namespace)}.to_string());
- assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{Vec<T>}).unwrap()).to_string(), quote!{<Vec<T> as apache_avro::schema::derive::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, enclosing_namespace)}.to_string());
- assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{AnyType}).unwrap()).to_string(), quote!{<AnyType as apache_avro::schema::derive::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, enclosing_namespace)}.to_string());
+ assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{i32}).unwrap()).to_string(), quote!{<i32 as apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, enclosing_namespace)}.to_string());
+ assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{Vec<T>}).unwrap()).to_string(), quote!{<Vec<T> as apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, enclosing_namespace)}.to_string());
+ assert_eq!(type_path_schema_expr(&syn::parse2::<TypePath>(quote!{AnyType}).unwrap()).to_string(), quote!{<AnyType as apache_avro::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, enclosing_namespace)}.to_string());
}
#[test]
diff --git a/avro_derive/tests/derive.rs b/avro_derive/tests/derive.rs
index 72c6db0..cf3be7e 100644
--- a/avro_derive/tests/derive.rs
+++ b/avro_derive/tests/derive.rs
@@ -17,7 +17,7 @@
use apache_avro::{
Reader, Schema, Writer, from_value,
- schema::{AvroSchema, derive::AvroSchemaComponent},
+ schema::{AvroSchema, AvroSchemaComponent},
};
use apache_avro_derive::*;
use proptest::prelude::*;