This is an automated email from the ASF dual-hosted git repository.

kriskras99 pushed a commit to branch reorganize/derive_traits
in repository https://gitbox.apache.org/repos/asf/avro-rs.git

commit 2d858e16219deb4b06ce0022a6b60f8c97ab51b3
Author: Kriskras99 <[email protected]>
AuthorDate: Fri Jan 23 22:26:00 2026 +0100

    chore: Move `AvroSchema` and `AvroSchemaComponent` to the `serde` module
---
 .../test_interop_single_object_encoding.rs         |   2 +-
 avro/src/lib.rs                                    |   4 +-
 avro/src/reader.rs                                 |   3 +-
 avro/src/schema/mod.rs                             | 440 +-------------------
 avro/src/serde/derive.rs                           | 450 +++++++++++++++++++++
 avro/src/serde/mod.rs                              |   2 +
 avro/src/writer.rs                                 |   4 +-
 avro_derive/tests/derive.rs                        |   6 +-
 8 files changed, 462 insertions(+), 449 deletions(-)

diff --git a/avro/examples/test_interop_single_object_encoding.rs 
b/avro/examples/test_interop_single_object_encoding.rs
index 61b1e6f..e65b35e 100644
--- a/avro/examples/test_interop_single_object_encoding.rs
+++ b/avro/examples/test_interop_single_object_encoding.rs
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use apache_avro::{schema::AvroSchema, types::Value};
+use apache_avro::{serde::AvroSchema, types::Value};
 use std::error::Error;
 
 struct InteropMessage;
diff --git a/avro/src/lib.rs b/avro/src/lib.rs
index 785d718..f60c8c2 100644
--- a/avro/src/lib.rs
+++ b/avro/src/lib.rs
@@ -982,8 +982,8 @@ pub use reader::{
     GenericSingleObjectReader, Reader, SpecificSingleObjectReader, 
from_avro_datum,
     from_avro_datum_reader_schemata, from_avro_datum_schemata, read_marker,
 };
-pub use schema::{AvroSchema, AvroSchemaComponent, Schema};
-pub use serde::{from_value, to_value};
+pub use schema::Schema;
+pub use serde::{AvroSchema, AvroSchemaComponent, from_value, to_value};
 pub use uuid::Uuid;
 pub use writer::{
     GenericSingleObjectWriter, SpecificSingleObjectWriter, Writer, 
WriterBuilder, to_avro_datum,
diff --git a/avro/src/reader.rs b/avro/src/reader.rs
index 23af5db..967edb5 100644
--- a/avro/src/reader.rs
+++ b/avro/src/reader.rs
@@ -23,9 +23,10 @@ use crate::{
     from_value,
     headers::{HeaderBuilder, RabinFingerprintHeader},
     schema::{
-        AvroSchema, Names, ResolvedOwnedSchema, ResolvedSchema, Schema, 
resolve_names,
+        Names, ResolvedOwnedSchema, ResolvedSchema, Schema, resolve_names,
         resolve_names_with_schemata,
     },
+    serde::AvroSchema,
     types::Value,
     util,
 };
diff --git a/avro/src/schema/mod.rs b/avro/src/schema/mod.rs
index f77854e..3e6e4b1 100644
--- a/avro/src/schema/mod.rs
+++ b/avro/src/schema/mod.rs
@@ -28,7 +28,7 @@ use serde::{
 };
 use serde_json::{Map, Value};
 use std::{
-    borrow::{Borrow, Cow},
+    borrow::Borrow,
     collections::{BTreeMap, HashMap, HashSet},
     fmt,
     fmt::Debug,
@@ -1262,333 +1262,6 @@ fn field_ordering_position(field: &str) -> 
Option<usize> {
         .map(|pos| pos + 1)
 }
 
-/// Trait for types that serve as an Avro data model. Derive implementation 
available
-/// through `derive` feature. Do not implement directly!
-/// Implement [`AvroSchemaComponent`] to get this trait
-/// through a blanket implementation.
-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(named_schemas, 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 + ?Sized,
-{
-    fn get_schema() -> Schema {
-        T::get_schema_in_ctxt(&mut HashMap::default(), &None)
-    }
-}
-
-macro_rules! impl_schema (
-    ($type:ty, $variant_constructor:expr) => (
-        impl AvroSchemaComponent for $type {
-            fn get_schema_in_ctxt(_: &mut Names, _: &Namespace) -> Schema {
-                $variant_constructor
-            }
-        }
-    );
-);
-
-impl_schema!(bool, Schema::Boolean);
-impl_schema!(i8, Schema::Int);
-impl_schema!(i16, Schema::Int);
-impl_schema!(i32, Schema::Int);
-impl_schema!(i64, Schema::Long);
-impl_schema!(u8, Schema::Int);
-impl_schema!(u16, Schema::Int);
-impl_schema!(u32, Schema::Long);
-impl_schema!(f32, Schema::Float);
-impl_schema!(f64, Schema::Double);
-impl_schema!(String, Schema::String);
-impl_schema!(str, Schema::String);
-impl_schema!(char, Schema::String);
-
-impl<T> AvroSchemaComponent for &T
-where
-    T: AvroSchemaComponent + ?Sized,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
-    }
-}
-
-impl<T> AvroSchemaComponent for &mut T
-where
-    T: AvroSchemaComponent + ?Sized,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
-    }
-}
-
-impl<T> AvroSchemaComponent for [T]
-where
-    T: AvroSchemaComponent,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        Schema::array(T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace))
-    }
-}
-
-impl<const N: usize, T> AvroSchemaComponent for [T; N]
-where
-    T: AvroSchemaComponent,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        Schema::array(T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace))
-    }
-}
-
-impl<T> AvroSchemaComponent for Vec<T>
-where
-    T: AvroSchemaComponent,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        Schema::array(T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace))
-    }
-}
-
-impl<T> AvroSchemaComponent for Option<T>
-where
-    T: AvroSchemaComponent,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        let variants = vec![
-            Schema::Null,
-            T::get_schema_in_ctxt(named_schemas, enclosing_namespace),
-        ];
-
-        Schema::Union(
-            UnionSchema::new(variants).expect("Option<T> must produce a valid 
(non-nested) union"),
-        )
-    }
-}
-
-impl<T> AvroSchemaComponent for Map<String, T>
-where
-    T: AvroSchemaComponent,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        Schema::map(T::get_schema_in_ctxt(named_schemas, enclosing_namespace))
-    }
-}
-
-impl<T> AvroSchemaComponent for HashMap<String, T>
-where
-    T: AvroSchemaComponent,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        Schema::map(T::get_schema_in_ctxt(named_schemas, enclosing_namespace))
-    }
-}
-
-impl<T> AvroSchemaComponent for Box<T>
-where
-    T: AvroSchemaComponent,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
-    }
-}
-
-impl<T> AvroSchemaComponent for std::sync::Mutex<T>
-where
-    T: AvroSchemaComponent,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
-    }
-}
-
-impl<T> AvroSchemaComponent for Cow<'_, T>
-where
-    T: AvroSchemaComponent + Clone,
-{
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
-    }
-}
-
-impl AvroSchemaComponent for core::time::Duration {
-    /// The schema is [`Schema::Duration`] with the name `duration`.
-    ///
-    /// This is a lossy conversion as this Avro type does not store the amount 
of nanoseconds.
-    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        let name = Name::new("duration")
-            .expect("Name is valid")
-            .fully_qualified_name(enclosing_namespace);
-        if named_schemas.contains_key(&name) {
-            Schema::Ref { name }
-        } else {
-            let schema = Schema::Duration(FixedSchema {
-                name: name.clone(),
-                aliases: None,
-                doc: None,
-                size: 12,
-                default: None,
-                attributes: Default::default(),
-            });
-            named_schemas.insert(name, schema.clone());
-            schema
-        }
-    }
-}
-
-impl AvroSchemaComponent for uuid::Uuid {
-    /// The schema is [`Schema::Uuid`] with the name `uuid`.
-    ///
-    /// The underlying schema is [`Schema::Fixed`] with a size of 16.
-    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        let name = Name::new("uuid")
-            .expect("Name is valid")
-            .fully_qualified_name(enclosing_namespace);
-        if named_schemas.contains_key(&name) {
-            Schema::Ref { name }
-        } else {
-            let schema = Schema::Uuid(UuidSchema::Fixed(FixedSchema {
-                name: name.clone(),
-                aliases: None,
-                doc: None,
-                size: 16,
-                default: None,
-                attributes: Default::default(),
-            }));
-            named_schemas.insert(name, schema.clone());
-            schema
-        }
-    }
-}
-
-impl AvroSchemaComponent for u64 {
-    /// The schema is [`Schema::Fixed`] of size 8 with the name `u64`.
-    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        let name = Name::new("u64")
-            .expect("Name is valid")
-            .fully_qualified_name(enclosing_namespace);
-        if named_schemas.contains_key(&name) {
-            Schema::Ref { name }
-        } else {
-            let schema = Schema::Fixed(FixedSchema {
-                name: name.clone(),
-                aliases: None,
-                doc: None,
-                size: 8,
-                default: None,
-                attributes: Default::default(),
-            });
-            named_schemas.insert(name, schema.clone());
-            schema
-        }
-    }
-}
-
-impl AvroSchemaComponent for u128 {
-    /// The schema is [`Schema::Fixed`] of size 16 with the name `u128`.
-    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        let name = Name::new("u128")
-            .expect("Name is valid")
-            .fully_qualified_name(enclosing_namespace);
-        if named_schemas.contains_key(&name) {
-            Schema::Ref { name }
-        } else {
-            let schema = Schema::Fixed(FixedSchema {
-                name: name.clone(),
-                aliases: None,
-                doc: None,
-                size: 16,
-                default: None,
-                attributes: Default::default(),
-            });
-            named_schemas.insert(name, schema.clone());
-            schema
-        }
-    }
-}
-
-impl AvroSchemaComponent for i128 {
-    /// The schema is [`Schema::Fixed`] of size 16 with the name `i128`.
-    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
-    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
-        let name = Name::new("i128")
-            .expect("Name is valid")
-            .fully_qualified_name(enclosing_namespace);
-        if named_schemas.contains_key(&name) {
-            Schema::Ref { name }
-        } else {
-            let schema = Schema::Fixed(FixedSchema {
-                name: name.clone(),
-                aliases: None,
-                doc: None,
-                size: 16,
-                default: None,
-                attributes: Default::default(),
-            });
-            named_schemas.insert(name, schema.clone());
-            schema
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -6359,117 +6032,6 @@ mod tests {
         Ok(())
     }
 
-    #[test]
-    fn avro_rs_401_str() -> TestResult {
-        let schema = str::get_schema();
-        assert_eq!(schema, Schema::String);
-
-        Ok(())
-    }
-
-    #[test]
-    fn avro_rs_401_references() -> TestResult {
-        let schema_ref = <&str>::get_schema();
-        let schema_ref_mut = <&mut str>::get_schema();
-
-        assert_eq!(schema_ref, Schema::String);
-        assert_eq!(schema_ref_mut, Schema::String);
-
-        Ok(())
-    }
-
-    #[test]
-    fn avro_rs_401_slice() -> TestResult {
-        let schema = <[u8]>::get_schema();
-        assert_eq!(schema, Schema::array(Schema::Int));
-
-        Ok(())
-    }
-
-    #[test]
-    fn avro_rs_401_array() -> TestResult {
-        let schema = <[u8; 55]>::get_schema();
-        assert_eq!(schema, Schema::array(Schema::Int));
-
-        Ok(())
-    }
-
-    #[test]
-    fn avro_rs_401_option_ref_slice_array() -> TestResult {
-        let schema = <Option<&[[u8; 55]]>>::get_schema();
-        assert_eq!(
-            schema,
-            Schema::union(vec![
-                Schema::Null,
-                Schema::array(Schema::array(Schema::Int))
-            ])?
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn avro_rs_414_char() -> TestResult {
-        let schema = char::get_schema();
-        assert_eq!(schema, Schema::String);
-
-        Ok(())
-    }
-
-    #[test]
-    fn avro_rs_414_u64() -> TestResult {
-        let schema = u64::get_schema();
-        assert_eq!(
-            schema,
-            Schema::Fixed(FixedSchema {
-                name: Name::new("u64")?,
-                aliases: None,
-                doc: None,
-                size: 8,
-                default: None,
-                attributes: Default::default(),
-            })
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn avro_rs_414_i128() -> TestResult {
-        let schema = i128::get_schema();
-        assert_eq!(
-            schema,
-            Schema::Fixed(FixedSchema {
-                name: Name::new("i128")?,
-                aliases: None,
-                doc: None,
-                size: 16,
-                default: None,
-                attributes: Default::default(),
-            })
-        );
-
-        Ok(())
-    }
-
-    #[test]
-    fn avro_rs_414_u128() -> TestResult {
-        let schema = u128::get_schema();
-        assert_eq!(
-            schema,
-            Schema::Fixed(FixedSchema {
-                name: Name::new("u128")?,
-                aliases: None,
-                doc: None,
-                size: 16,
-                default: None,
-                attributes: Default::default(),
-            })
-        );
-
-        Ok(())
-    }
-
     #[test]
     fn avro_rs_420_independent_canonical_form() -> TestResult {
         let (record, schemata) = Schema::parse_str_with_list(
diff --git a/avro/src/serde/derive.rs b/avro/src/serde/derive.rs
new file mode 100644
index 0000000..e6e4e16
--- /dev/null
+++ b/avro/src/serde/derive.rs
@@ -0,0 +1,450 @@
+use crate::Schema;
+use crate::schema::{FixedSchema, Name, Names, Namespace, UnionSchema, 
UuidSchema};
+use serde_json::Map;
+use std::borrow::Cow;
+use std::collections::HashMap;
+
+/// Trait for types that serve as an Avro data model. Derive implementation 
available
+/// through `derive` feature. Do not implement directly!
+/// Implement [`AvroSchemaComponent`] to get this trait
+/// through a blanket implementation.
+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(named_schemas, 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 + ?Sized,
+{
+    fn get_schema() -> Schema {
+        T::get_schema_in_ctxt(&mut HashMap::default(), &None)
+    }
+}
+
+macro_rules! impl_schema (
+    ($type:ty, $variant_constructor:expr) => (
+        impl AvroSchemaComponent for $type {
+            fn get_schema_in_ctxt(_: &mut Names, _: &Namespace) -> Schema {
+                $variant_constructor
+            }
+        }
+    );
+);
+
+impl_schema!(bool, Schema::Boolean);
+impl_schema!(i8, Schema::Int);
+impl_schema!(i16, Schema::Int);
+impl_schema!(i32, Schema::Int);
+impl_schema!(i64, Schema::Long);
+impl_schema!(u8, Schema::Int);
+impl_schema!(u16, Schema::Int);
+impl_schema!(u32, Schema::Long);
+impl_schema!(f32, Schema::Float);
+impl_schema!(f64, Schema::Double);
+impl_schema!(String, Schema::String);
+impl_schema!(str, Schema::String);
+impl_schema!(char, Schema::String);
+
+impl<T> AvroSchemaComponent for &T
+where
+    T: AvroSchemaComponent + ?Sized,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
+    }
+}
+
+impl<T> AvroSchemaComponent for &mut T
+where
+    T: AvroSchemaComponent + ?Sized,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
+    }
+}
+
+impl<T> AvroSchemaComponent for [T]
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        Schema::array(T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace))
+    }
+}
+
+impl<const N: usize, T> AvroSchemaComponent for [T; N]
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        Schema::array(T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace))
+    }
+}
+
+impl<T> AvroSchemaComponent for Vec<T>
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        Schema::array(T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace))
+    }
+}
+
+impl<T> AvroSchemaComponent for Option<T>
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        let variants = vec![
+            Schema::Null,
+            T::get_schema_in_ctxt(named_schemas, enclosing_namespace),
+        ];
+
+        Schema::Union(
+            UnionSchema::new(variants).expect("Option<T> must produce a valid 
(non-nested) union"),
+        )
+    }
+}
+
+impl<T> AvroSchemaComponent for Map<String, T>
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        Schema::map(T::get_schema_in_ctxt(named_schemas, enclosing_namespace))
+    }
+}
+
+impl<T> AvroSchemaComponent for HashMap<String, T>
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        Schema::map(T::get_schema_in_ctxt(named_schemas, enclosing_namespace))
+    }
+}
+
+impl<T> AvroSchemaComponent for Box<T>
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
+    }
+}
+
+impl<T> AvroSchemaComponent for std::sync::Mutex<T>
+where
+    T: AvroSchemaComponent,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
+    }
+}
+
+impl<T> AvroSchemaComponent for Cow<'_, T>
+where
+    T: AvroSchemaComponent + Clone,
+{
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
+    }
+}
+
+impl AvroSchemaComponent for core::time::Duration {
+    /// The schema is [`Schema::Duration`] with the name `duration`.
+    ///
+    /// This is a lossy conversion as this Avro type does not store the amount 
of nanoseconds.
+    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        let name = Name::new("duration")
+            .expect("Name is valid")
+            .fully_qualified_name(enclosing_namespace);
+        if named_schemas.contains_key(&name) {
+            Schema::Ref { name }
+        } else {
+            let schema = Schema::Duration(FixedSchema {
+                name: name.clone(),
+                aliases: None,
+                doc: None,
+                size: 12,
+                default: None,
+                attributes: Default::default(),
+            });
+            named_schemas.insert(name, schema.clone());
+            schema
+        }
+    }
+}
+
+impl AvroSchemaComponent for uuid::Uuid {
+    /// The schema is [`Schema::Uuid`] with the name `uuid`.
+    ///
+    /// The underlying schema is [`Schema::Fixed`] with a size of 16.
+    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        let name = Name::new("uuid")
+            .expect("Name is valid")
+            .fully_qualified_name(enclosing_namespace);
+        if named_schemas.contains_key(&name) {
+            Schema::Ref { name }
+        } else {
+            let schema = Schema::Uuid(UuidSchema::Fixed(FixedSchema {
+                name: name.clone(),
+                aliases: None,
+                doc: None,
+                size: 16,
+                default: None,
+                attributes: Default::default(),
+            }));
+            named_schemas.insert(name, schema.clone());
+            schema
+        }
+    }
+}
+
+impl AvroSchemaComponent for u64 {
+    /// The schema is [`Schema::Fixed`] of size 8 with the name `u64`.
+    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        let name = Name::new("u64")
+            .expect("Name is valid")
+            .fully_qualified_name(enclosing_namespace);
+        if named_schemas.contains_key(&name) {
+            Schema::Ref { name }
+        } else {
+            let schema = Schema::Fixed(FixedSchema {
+                name: name.clone(),
+                aliases: None,
+                doc: None,
+                size: 8,
+                default: None,
+                attributes: Default::default(),
+            });
+            named_schemas.insert(name, schema.clone());
+            schema
+        }
+    }
+}
+
+impl AvroSchemaComponent for u128 {
+    /// The schema is [`Schema::Fixed`] of size 16 with the name `u128`.
+    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        let name = Name::new("u128")
+            .expect("Name is valid")
+            .fully_qualified_name(enclosing_namespace);
+        if named_schemas.contains_key(&name) {
+            Schema::Ref { name }
+        } else {
+            let schema = Schema::Fixed(FixedSchema {
+                name: name.clone(),
+                aliases: None,
+                doc: None,
+                size: 16,
+                default: None,
+                attributes: Default::default(),
+            });
+            named_schemas.insert(name, schema.clone());
+            schema
+        }
+    }
+}
+
+impl AvroSchemaComponent for i128 {
+    /// The schema is [`Schema::Fixed`] of size 16 with the name `i128`.
+    #[expect(clippy::map_entry, reason = "We don't use the value from the 
map")]
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        let name = Name::new("i128")
+            .expect("Name is valid")
+            .fully_qualified_name(enclosing_namespace);
+        if named_schemas.contains_key(&name) {
+            Schema::Ref { name }
+        } else {
+            let schema = Schema::Fixed(FixedSchema {
+                name: name.clone(),
+                aliases: None,
+                doc: None,
+                size: 16,
+                default: None,
+                attributes: Default::default(),
+            });
+            named_schemas.insert(name, schema.clone());
+            schema
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::schema::{FixedSchema, Name};
+    use crate::{AvroSchema, Schema};
+    use apache_avro_test_helper::TestResult;
+
+    #[test]
+    fn avro_rs_401_str() -> TestResult {
+        let schema = str::get_schema();
+        assert_eq!(schema, Schema::String);
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_401_references() -> TestResult {
+        let schema_ref = <&str>::get_schema();
+        let schema_ref_mut = <&mut str>::get_schema();
+
+        assert_eq!(schema_ref, Schema::String);
+        assert_eq!(schema_ref_mut, Schema::String);
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_401_slice() -> TestResult {
+        let schema = <[u8]>::get_schema();
+        assert_eq!(schema, Schema::array(Schema::Int));
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_401_array() -> TestResult {
+        let schema = <[u8; 55]>::get_schema();
+        assert_eq!(schema, Schema::array(Schema::Int));
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_401_option_ref_slice_array() -> TestResult {
+        let schema = <Option<&[[u8; 55]]>>::get_schema();
+        assert_eq!(
+            schema,
+            Schema::union(vec![
+                Schema::Null,
+                Schema::array(Schema::array(Schema::Int))
+            ])?
+        );
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_414_char() -> TestResult {
+        let schema = char::get_schema();
+        assert_eq!(schema, Schema::String);
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_414_u64() -> TestResult {
+        let schema = u64::get_schema();
+        assert_eq!(
+            schema,
+            Schema::Fixed(FixedSchema {
+                name: Name::new("u64")?,
+                aliases: None,
+                doc: None,
+                size: 8,
+                default: None,
+                attributes: Default::default(),
+            })
+        );
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_414_i128() -> TestResult {
+        let schema = i128::get_schema();
+        assert_eq!(
+            schema,
+            Schema::Fixed(FixedSchema {
+                name: Name::new("i128")?,
+                aliases: None,
+                doc: None,
+                size: 16,
+                default: None,
+                attributes: Default::default(),
+            })
+        );
+
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_414_u128() -> TestResult {
+        let schema = u128::get_schema();
+        assert_eq!(
+            schema,
+            Schema::Fixed(FixedSchema {
+                name: Name::new("u128")?,
+                aliases: None,
+                doc: None,
+                size: 16,
+                default: None,
+                attributes: Default::default(),
+            })
+        );
+
+        Ok(())
+    }
+}
diff --git a/avro/src/serde/mod.rs b/avro/src/serde/mod.rs
index 01852a8..9c1dea4 100644
--- a/avro/src/serde/mod.rs
+++ b/avro/src/serde/mod.rs
@@ -16,11 +16,13 @@
 // under the License.
 
 mod de;
+mod derive;
 mod ser;
 pub(crate) mod ser_schema;
 mod util;
 mod with;
 
 pub use de::from_value;
+pub use derive::{AvroSchema, AvroSchemaComponent};
 pub use ser::to_value;
 pub use with::{bytes, bytes_opt, fixed, fixed_opt, slice, slice_opt};
diff --git a/avro/src/writer.rs b/avro/src/writer.rs
index 5573e25..4ec219f 100644
--- a/avro/src/writer.rs
+++ b/avro/src/writer.rs
@@ -21,8 +21,8 @@ use crate::{
     encode::{encode, encode_internal, encode_to_vec},
     error::Details,
     headers::{HeaderBuilder, RabinFingerprintHeader},
-    schema::{AvroSchema, Name, ResolvedOwnedSchema, ResolvedSchema, Schema},
-    serde::ser_schema::SchemaAwareWriteSerializer,
+    schema::{Name, ResolvedOwnedSchema, ResolvedSchema, Schema},
+    serde::{AvroSchema, ser_schema::SchemaAwareWriteSerializer},
     types::Value,
 };
 use serde::Serialize;
diff --git a/avro_derive/tests/derive.rs b/avro_derive/tests/derive.rs
index a9012ed..40c1a6a 100644
--- a/avro_derive/tests/derive.rs
+++ b/avro_derive/tests/derive.rs
@@ -17,10 +17,8 @@
 
 use apache_avro::{
     Reader, Schema, Writer, from_value,
-    schema::{
-        Alias, AvroSchema, AvroSchemaComponent, EnumSchema, FixedSchema, Name, 
Names, Namespace,
-        RecordSchema,
-    },
+    schema::{Alias, EnumSchema, FixedSchema, Name, Names, Namespace, 
RecordSchema},
+    serde::{AvroSchema, AvroSchemaComponent},
 };
 use apache_avro_derive::*;
 use proptest::prelude::*;

Reply via email to