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

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

commit f69dc55cf724136721992590c405d0b430b9b8e1
Author: default <[email protected]>
AuthorDate: Fri Dec 12 11:14:49 2025 +0000

    feat: Improve documentation for AvroSchema trait and derive
---
 .../test_interop_single_object_encoding.rs         |   2 +-
 avro/src/lib.rs                                    |  27 +-
 avro/src/reader.rs                                 |   3 +-
 avro/src/schema.rs                                 | 237 +--------------
 avro/src/schema_compatibility.rs                   |   2 +-
 avro/src/serde/de.rs                               |   4 +-
 avro/src/serde/mod.rs                              | 336 ++++++++++++++++++++-
 avro/src/serde/ser.rs                              |  36 +--
 avro/src/{bytes.rs => serde/serde_with.rs}         | 169 ++++++-----
 avro/src/types.rs                                  |  21 +-
 avro/src/writer.rs                                 |   4 +-
 avro/tests/avro-rs-285-bytes_deserialization.rs    |   2 +-
 avro_derive/src/lib.rs                             |  24 +-
 avro_derive/tests/derive.rs                        |   2 +-
 14 files changed, 489 insertions(+), 380 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 5c744ff..6eeed38 100644
--- a/avro/src/lib.rs
+++ b/avro/src/lib.rs
@@ -868,13 +868,13 @@
 //!
 //!  #[derive(Debug, Deserialize, Serialize)]
 //!  struct SampleStruct {
-//!   #[serde(with = "apache_avro::serde_avro_bytes")]
+//!   #[serde(with = "apache_avro::serde::avro_bytes")]
 //!   non_optional_bytes: Vec<u8>,
-//!   #[serde(with = "apache_avro::serde_avro_bytes_opt")]
+//!   #[serde(with = "apache_avro::serde::avro_bytes_opt")]
 //!   optional_bytes: Option<Vec<u8>>,
-//!   #[serde(with = "apache_avro::serde_avro_fixed")]
+//!   #[serde(with = "apache_avro::serde::avro_fixed")]
 //!   non_optional_fixed: [u8; 6],
-//!   #[serde(with = "apache_avro::serde_avro_fixed_opt")]
+//!   #[serde(with = "apache_avro::serde::avro_fixed_opt")]
 //!   optional_fixed: Option<[u8; 6]>,
 //!  }
 //! ```
@@ -886,7 +886,7 @@
 //!
 //! #[derive(Debug, Deserialize, PartialEq, Serialize)]
 //! struct ExampleByteArray {
-//!     #[serde(with = "apache_avro::serde_avro_bytes_opt")]
+//!     #[serde(with = "apache_avro::serde::avro_bytes_opt")]
 //!     data_bytes: Option<Vec<u8>>,
 //!     description: Option<String>,
 //! }
@@ -939,18 +939,16 @@
 //! }
 //! ```
 //!
-//! Full implementation and other options for things like fixed byte arrays 
can be found in src/bytes.rs
+//! Full implementation and other options for things like fixed byte arrays 
can be found in src/serde_with
 //!
 
 mod bigdecimal;
-mod bytes;
 mod codec;
 mod decimal;
 mod decode;
 mod duration;
 mod encode;
 mod reader;
-mod serde;
 mod writer;
 
 pub mod error;
@@ -959,17 +957,12 @@ pub mod rabin;
 pub mod schema;
 pub mod schema_compatibility;
 pub mod schema_equality;
+pub mod serde;
 pub mod types;
 pub mod util;
 pub mod validator;
 
-pub use crate::{
-    bigdecimal::BigDecimal,
-    bytes::{
-        serde_avro_bytes, serde_avro_bytes_opt, serde_avro_fixed, 
serde_avro_fixed_opt,
-        serde_avro_slice, serde_avro_slice_opt,
-    },
-};
+pub use crate::bigdecimal::BigDecimal;
 #[cfg(feature = "bzip")]
 pub use codec::bzip::Bzip2Settings;
 #[cfg(feature = "xz")]
@@ -984,8 +977,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, Schema};
-pub use serde::{de::from_value, ser::to_value};
+pub use schema::Schema;
+pub use serde::{AvroSchema, 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.rs b/avro/src/schema.rs
index cba069b..f73b165 100644
--- a/avro/src/schema.rs
+++ b/avro/src/schema.rs
@@ -245,7 +245,7 @@ pub type Documentation = Option<String>;
 /// Represents the aliases for Named Schema
 pub type Aliases = Option<Vec<Alias>>;
 /// Represents Schema lookup within a schema env
-pub(crate) type Names = HashMap<Name, Schema>;
+pub type Names = HashMap<Name, Schema>;
 /// Represents Schema lookup within a schema
 pub type NamesRef<'a> = HashMap<Name, &'a Schema>;
 /// Represents the namespace for Named Schema
@@ -320,17 +320,19 @@ impl Name {
     }
 
     /// Return the fully qualified name needed for indexing or searching for 
the schema within a schema/schema env context. Puts the enclosing namespace 
into the name's namespace for clarity in schema/schema env parsing
-    /// ```ignore
-    /// use apache_avro::schema::Name;
-    ///
+    /// ```
+    /// # use apache_avro::{Error, schema::Name};
+    /// # fn main() -> Result<(), Error> {
     /// assert_eq!(
-    /// 
Name::new("some_name")?.fully_qualified_name(&Some("some_namespace".into())),
-    /// Name::new("some_namespace.some_name")?
+    ///     
Name::new("some_name")?.fully_qualified_name(&Some("some_namespace".into())),
+    ///     Name::new("some_namespace.some_name")?
     /// );
     /// assert_eq!(
-    /// 
Name::new("some_namespace.some_name")?.fully_qualified_name(&Some("other_namespace".into())),
-    /// Name::new("some_namespace.some_name")?
+    ///     
Name::new("some_namespace.some_name")?.fully_qualified_name(&Some("other_namespace".into())),
+    ///     Name::new("some_namespace.some_name")?
     /// );
+    /// # Ok(())
+    /// # }
     /// ```
     pub fn fully_qualified_name(&self, enclosing_namespace: &Namespace) -> 
Name {
         Name {
@@ -974,7 +976,7 @@ pub struct UnionSchema {
     // schema index given a value.
     // **NOTE** that this approach does not work for named types, and will 
have to be modified
     // to support that. A simple solution is to also keep a mapping of the 
names used.
-    variant_index: BTreeMap<SchemaKind, usize>,
+    pub(crate) variant_index: BTreeMap<SchemaKind, usize>,
 }
 
 impl UnionSchema {
@@ -2429,7 +2431,8 @@ impl Serialize for RecordField {
 }
 
 /// Parses a **valid** avro schema into the Parsing Canonical Form.
-/// 
https://avro.apache.org/docs/current/specification/#parsing-canonical-form-for-schemas
+///
+/// 
<https://avro.apache.org/docs/current/specification/#parsing-canonical-form-for-schemas>
 fn parsing_canonical_form(schema: &Value, defined_names: &mut HashSet<String>) 
-> String {
     match schema {
         Value::Object(map) => pcf_map(map, defined_names),
@@ -2566,220 +2569,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 `apache_avro::schema::derive::AvroSchemaComponent` to get this 
trait
-/// through a blanket implementation.
-pub trait AvroSchema {
-    fn get_schema() -> 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,
-    {
-        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!(uuid::Uuid, Schema::Uuid(UuidSchema::String));
-
-    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 inner_schema = T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace);
-            Schema::Union(UnionSchema {
-                schemas: vec![Schema::Null, inner_schema.clone()],
-                variant_index: [Schema::Null, inner_schema]
-                    .iter()
-                    .enumerate()
-                    .map(|(idx, s)| (SchemaKind::from(s), idx))
-                    .collect(),
-            })
-        }
-    }
-
-    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 {
-        fn get_schema_in_ctxt(
-            named_schemas: &mut Names,
-            enclosing_namespace: &Namespace,
-        ) -> Schema {
-            let name = Name {
-                name: "duration".to_string(),
-                namespace: enclosing_namespace.clone(),
-            };
-            named_schemas
-                .entry(name.clone())
-                .or_insert(Schema::Duration(FixedSchema {
-                    name,
-                    aliases: None,
-                    doc: None,
-                    size: 12,
-                    default: None,
-                    attributes: Default::default(),
-                }))
-                .clone()
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/avro/src/schema_compatibility.rs b/avro/src/schema_compatibility.rs
index 74ae558..281a293 100644
--- a/avro/src/schema_compatibility.rs
+++ b/avro/src/schema_compatibility.rs
@@ -103,7 +103,7 @@ impl Checker {
         hasher.finish()
     }
 
-    /// The actual implementation of [`full_match_schemas`] but without the 
recursion protection.
+    /// The actual implementation of [`Self::full_match_schemas`] but without 
the recursion protection.
     ///
     /// This function should never be called directly as it can recurse 
infinitely on recursive types.
     #[rustfmt::skip]
diff --git a/avro/src/serde/de.rs b/avro/src/serde/de.rs
index ce42576..bd73549 100644
--- a/avro/src/serde/de.rs
+++ b/avro/src/serde/de.rs
@@ -16,7 +16,7 @@
 // under the License.
 
 //! Logic for serde-compatible deserialization.
-use crate::{Error, bytes::DE_BYTES_BORROWED, error::Details, types::Value};
+use crate::{Error, error::Details, serde::serde_with::DE_BYTES_BORROWED, 
types::Value};
 use serde::{
     Deserialize,
     de::{self, DeserializeSeed, Deserializer as _, Visitor},
@@ -772,7 +772,7 @@ impl<'de> de::Deserializer<'de> for StringDeserializer {
     }
 }
 
-/// Interpret a `Value` as an instance of type `D`.
+/// Deserialize from a [`Value`].
 ///
 /// This conversion can fail if the structure of the `Value` does not match the
 /// structure expected by `D`.
diff --git a/avro/src/serde/mod.rs b/avro/src/serde/mod.rs
index efd1032..783d15f 100644
--- a/avro/src/serde/mod.rs
+++ b/avro/src/serde/mod.rs
@@ -15,7 +15,337 @@
 // specific language governing permissions and limitations
 // under the License.
 
-pub mod de;
-pub mod ser;
-pub mod ser_schema;
+//! Everything needed to use this crate with Serde.
+//!
+//! # Using `apache-avro` for `serde`
+//!
+//! Avro is a schema-based format, this means it requires a few extra steps to 
use compared to
+//! a data format like JSON.
+//!
+//! ## Schemas
+//! It's strongly recommended to derive the schemas for your types using the 
[`AvroSchema`] derive macro.
+//! The macro uses the Serde attributes to generate a matching schema and 
checks that no attributes are
+//! used that are incompatible with the Serde implementation in this crate. 
See the trait documenation for
+//! details on how to change the generated schema.
+//!
+//! Alternatively, you can write your own schema. If you go down this path, it 
is recommended you start with
+//! the schema derived by [`AvroSchema`] and then modify it to fit your needs.
+//!
+//! ### Using existing schemas
+//! If you have schemas that are already being used in other parts of your 
software stack, generating types
+//! from the schema can be very useful. There is a **third-party** crate 
[`rsgen-avro`] that implements this.
+//!
+//! ## Reading and writing data
+//!
+//! ```
+//! # use std::io::Cursor;
+//! # use serde::{Serialize, Deserialize};
+//! # use apache_avro::{AvroSchema, Error, Reader, Writer, serde::{from_value, 
to_value}};
+//! #
+//! # #[derive(PartialEq, Debug)]
+//! #[derive(Serialize, Deserialize, AvroSchema)]
+//! struct Foo {
+//!     a: i64,
+//!     b: String,
+//! }
+//!
+//! # fn main() -> Result<(), Error> {
+//! let schema = Foo::get_schema();
+//! // A writer needs the schema of the type that is going to be written
+//! let mut writer = Writer::new(&schema, Vec::new())?;
+//!
+//! let foo = Foo {
+//!     a: 42,
+//!     b: "Hello".to_string(),
+//! };
+//!
+//! // There are two ways to serialize data.
+//! // 1: Serialize directly to the writer:
+//! writer.append_ser(&foo)?;
+//! // 2: First serialize to an Avro `Value` then write that:
+//! let foo_value = to_value(&foo)?;
+//! writer.append(foo_value)?;
+//!
+//! // Always flush or consume the writer
+//! let data = writer.into_inner()?;
+//!
+//! // The reader does not need a schema as it's included in the data
+//! let reader = Reader::new(Cursor::new(data))?;
+//! // The reader is an iterator
+//! for result in reader {
+//!     let value = result?;
+//!     let new_foo: Foo = from_value(&value)?;
+//!     assert_eq!(new_foo, foo);
+//! }
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! [`rsgen-avro`]: https://docs.rs/rsgen-avro/latest/rsgen_avro/
+
+mod de;
+mod ser;
+mod ser_schema;
+mod serde_with;
 mod util;
+
+pub use de::from_value;
+pub use ser::to_value;
+pub(crate) use ser_schema::SchemaAwareWriteSerializer;
+
+pub use serde_with::{
+    avro_bytes, avro_bytes_opt, avro_fixed, avro_fixed_opt, avro_slice, 
avro_slice_opt,
+};
+
+use crate::{
+    Schema,
+    schema::{FixedSchema, Name, Names, Namespace, SchemaKind, UnionSchema},
+};
+
+/// Trait for types that serve as an Avro data model.
+///
+/// Do not implement directly! Implement [`AvroSchemaComponent`] to get this 
trait through
+/// a blanket implementation or use the derive macro.
+///
+/// # Deriving `AvroSchema`
+///
+/// Using the custom derive requires that you enable the `"derive"` cargo
+/// feature in your `Cargo.toml`:
+///
+/// ```toml
+/// [dependencies]
+/// apache-avro = { version = "..", features = ["derive"] }
+/// ```
+///
+/// Then, you add the `#[derive(AvroSchema)]` annotation to your `struct` and
+/// `enum` type definition:
+///
+/// ```
+/// # use serde::{Serialize, Deserialize};
+/// # use apache_avro::AvroSchema;
+/// #[derive(AvroSchema, Serialize, Deserialize)]
+/// pub struct Foo {
+///     bar: Vec<Bar>,
+/// }
+///
+/// #[derive(AvroSchema, Serialize, Deserialize)]
+/// pub enum Bar {
+///     Spam,
+///     Maps
+/// }
+/// ```
+///
+/// This will implement [`AvroSchemaComponent`] for the type, and `AvroSchema`
+/// through the blanket implementation for `T: AvroSchemaComponent`.
+///
+/// Every member of the `struct` and `enum` must also implement 
`AvroSchemaComponent`.
+///
+/// # Compatibility with Serde attributes
+///
+/// The derive macro is compatible with most Serde attributes. It is 
incompatible with
+/// the following attributes:
+///
+/// - Container attributes
+///     - `tag`
+///     - `content`
+///     - `untagged`
+///     - `variant_identifier`
+///     - `field_identifier`
+///     - `remote`
+///     - `transparent`
+///     - `rename_all(serialize = "..", deserialize = "..")` where `serialize` 
!= `deserialize`
+/// - Variant attributes
+///     - `other`
+///     - `untagged`
+/// - Field attributes
+///     - `getter`
+///
+/// The Serde attributes `skip_serializing` and `skip_serializing_if` require 
the `#[avro(default = "..")]`
+/// attribute because Avro does not support skipping fields.
+pub trait AvroSchema {
+    fn get_schema() -> Schema;
+}
+
+/// Trait for types that serve as fully defined components inside an Avro data 
model.
+///
+/// This can be derived via the [`AvroSchema`] derive.
+///
+/// # Implementation guide
+///
+/// ### Simple implementation
+/// To construct a unnamed simple schema, it is possible to ignore the input 
argument making the
+/// general form implementation look like
+/// ```
+/// # use apache_avro::{Schema, schema::{Names, Namespace}, 
serde::AvroSchemaComponent};
+/// # struct AType;
+/// impl AvroSchemaComponent for AType {
+///     fn get_schema_in_ctxt(_names: &mut Names, _enclosing_namespace: 
&Namespace) -> Schema {
+///        Schema::Int
+///    }
+/// }
+/// ```
+/// ### 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
+/// ```
+/// # use apache_avro::{Schema, schema::{Names, Namespace}, 
serde::AvroSchemaComponent};
+/// # struct InnerType;
+/// # impl AvroSchemaComponent for InnerType {
+/// #    fn get_schema_in_ctxt(_names: &mut Names, _enclosing_namespace: 
&Namespace) -> Schema {
+/// #       Schema::Int
+/// #    }
+/// # }
+/// # struct PassthroughType(InnerType);
+/// impl AvroSchemaComponent for PassthroughType {
+///     fn get_schema_in_ctxt(names: &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
+/// # use apache_avro::{Schema, schema::{Name, Names, Namespace}, 
serde::AvroSchemaComponent};
+/// 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 =  
Name::new("MyName").unwrap().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,
+{
+    fn get_schema() -> Schema {
+        T::get_schema_in_ctxt(&mut std::collections::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!(uuid::Uuid, Schema::Uuid(crate::schema::UuidSchema::String));
+
+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 inner_schema = T::get_schema_in_ctxt(named_schemas, 
enclosing_namespace);
+        Schema::Union(UnionSchema {
+            schemas: vec![Schema::Null, inner_schema.clone()],
+            variant_index: [Schema::Null, inner_schema]
+                .iter()
+                .enumerate()
+                .map(|(idx, s)| (SchemaKind::from(s), idx))
+                .collect(),
+        })
+    }
+}
+
+impl<T> AvroSchemaComponent for serde_json::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 std::collections::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 std::borrow::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 {
+    fn get_schema_in_ctxt(named_schemas: &mut Names, enclosing_namespace: 
&Namespace) -> Schema {
+        let name = Name {
+            name: "duration".to_string(),
+            namespace: enclosing_namespace.clone(),
+        };
+        named_schemas
+            .entry(name.clone())
+            .or_insert(Schema::Duration(FixedSchema {
+                name,
+                aliases: None,
+                doc: None,
+                size: 12,
+                default: None,
+                attributes: Default::default(),
+            }))
+            .clone()
+    }
+}
diff --git a/avro/src/serde/ser.rs b/avro/src/serde/ser.rs
index d78f501..97bf7f6 100644
--- a/avro/src/serde/ser.rs
+++ b/avro/src/serde/ser.rs
@@ -18,14 +18,14 @@
 //! Logic for serde-compatible serialization.
 use crate::{
     Error,
-    bytes::{BytesType, SER_BYTES_TYPE},
+    serde::serde_with::{BytesType, SER_BYTES_TYPE},
     types::Value,
 };
 use serde::{Serialize, ser};
 use std::{collections::HashMap, iter::once};
 
-#[derive(Clone, Default)]
-pub struct Serializer {}
+#[derive(Clone, Copy)]
+pub struct Serializer;
 
 pub struct SeqSerializer {
     items: Vec<Value>,
@@ -192,7 +192,7 @@ impl<'b> ser::Serializer for &'b mut Serializer {
     where
         T: Serialize + ?Sized,
     {
-        let v = value.serialize(&mut Serializer::default())?;
+        let v = value.serialize(&mut Serializer)?;
         Ok(Value::from(Some(v)))
     }
 
@@ -304,8 +304,7 @@ impl ser::SerializeSeq for SeqSerializer {
     where
         T: Serialize + ?Sized,
     {
-        self.items
-            .push(value.serialize(&mut Serializer::default())?);
+        self.items.push(value.serialize(&mut Serializer)?);
         Ok(())
     }
 
@@ -356,7 +355,7 @@ impl ser::SerializeSeq for SeqVariantSerializer<'_> {
     {
         self.items.push(Value::Union(
             self.index,
-            Box::new(value.serialize(&mut Serializer::default())?),
+            Box::new(value.serialize(&mut Serializer)?),
         ));
         Ok(())
     }
@@ -396,7 +395,7 @@ impl ser::SerializeMap for MapSerializer {
     where
         T: Serialize + ?Sized,
     {
-        let key = key.serialize(&mut Serializer::default())?;
+        let key = key.serialize(&mut Serializer)?;
 
         if let Value::String(key) = key {
             self.indices.insert(key, self.values.len());
@@ -410,8 +409,7 @@ impl ser::SerializeMap for MapSerializer {
     where
         T: Serialize + ?Sized,
     {
-        self.values
-            .push(value.serialize(&mut Serializer::default())?);
+        self.values.push(value.serialize(&mut Serializer)?);
         Ok(())
     }
 
@@ -435,10 +433,8 @@ impl ser::SerializeStruct for StructSerializer {
     where
         T: Serialize + ?Sized,
     {
-        self.fields.push((
-            name.to_owned(),
-            value.serialize(&mut Serializer::default())?,
-        ));
+        self.fields
+            .push((name.to_owned(), value.serialize(&mut Serializer)?));
         Ok(())
     }
 
@@ -455,10 +451,8 @@ impl ser::SerializeStructVariant for 
StructVariantSerializer<'_> {
     where
         T: Serialize + ?Sized,
     {
-        self.fields.push((
-            name.to_owned(),
-            value.serialize(&mut Serializer::default())?,
-        ));
+        self.fields
+            .push((name.to_owned(), value.serialize(&mut Serializer)?));
         Ok(())
     }
 
@@ -476,17 +470,17 @@ impl ser::SerializeStructVariant for 
StructVariantSerializer<'_> {
     }
 }
 
-/// Interpret a serializeable instance as a `Value`.
+/// Serialize to a [`Value`].
 ///
 /// This conversion can fail if the value is not valid as per the Avro 
specification.
 /// e.g: `HashMap` with non-string keys.
 ///
 /// This function does not work if `S` has any fields (recursively) that have 
the `#[serde(flatten)]`
-/// attribute. Please use [`Writer::append_ser`] if that's the case.
+/// attribute. Please use [`Writer::append_ser`] instead.
 ///
 /// [`Writer::append_ser`]: crate::Writer::append_ser
 pub fn to_value<S: Serialize>(value: S) -> Result<Value, Error> {
-    let mut serializer = Serializer::default();
+    let mut serializer = Serializer;
     value.serialize(&mut serializer)
 }
 
diff --git a/avro/src/bytes.rs b/avro/src/serde/serde_with.rs
similarity index 81%
rename from avro/src/bytes.rs
rename to avro/src/serde/serde_with.rs
index 8ac98b5..84ca031 100644
--- a/avro/src/bytes.rs
+++ b/avro/src/serde/serde_with.rs
@@ -18,14 +18,14 @@
 use std::cell::Cell;
 
 thread_local! {
-    /// A thread local that is used to decide how to serialize Rust bytes into 
an Avro
-    /// `types::Value` of type bytes.
+    /// A thread local that is used to decide if Rust bytes need to be 
serialized to
+    /// [`Value::Bytes`] or [`Value::Fixed`].
     ///
     /// Relies on the fact that serde's serialization process is 
single-threaded.
     pub(crate) static SER_BYTES_TYPE: Cell<BytesType> = const { 
Cell::new(BytesType::Bytes) };
 
-    /// A thread local that is used to decide how to deserialize an Avro 
`types::Value`
-    /// of type bytes into Rust bytes.
+    /// A thread local that is used to decide if a `Value::Bytes` needs to be 
deserialized to
+    /// a `Vec` or slice.
     ///
     /// Relies on the fact that serde's deserialization process is 
single-threaded.
     pub(crate) static DE_BYTES_BORROWED: Cell<bool> = const { Cell::new(false) 
};
@@ -40,23 +40,22 @@ pub(crate) enum BytesType {
 /// Efficient (de)serialization of Avro bytes values.
 ///
 /// This module is intended to be used through the Serde `with` attribute. Use
-/// [`serde_avro_bytes_opt`](crate::serde_avro_bytes_opt) for optional bytes.
+/// [`avro_bytes_opt`] for optional bytes.
 ///
-/// See usage with below example:
 /// ```rust
-/// use apache_avro::{serde_avro_bytes, serde_avro_fixed};
+/// use apache_avro::serde::serde_with::{avro_bytes, avro_fixed};
 /// use serde::{Deserialize, Serialize};
 ///
 /// #[derive(Serialize, Deserialize)]
 /// struct StructWithBytes {
-///     #[serde(with = "serde_avro_bytes")]
+///     #[serde(with = "avro_bytes")]
 ///     vec_field: Vec<u8>,
 ///
-///     #[serde(with = "serde_avro_fixed")]
+///     #[serde(with = "avro_fixed")]
 ///     fixed_field: [u8; 6],
 /// }
 /// ```
-pub mod serde_avro_bytes {
+pub mod avro_bytes {
     use serde::{Deserializer, Serializer};
 
     pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
@@ -77,23 +76,22 @@ pub mod serde_avro_bytes {
 /// Efficient (de)serialization of optional Avro bytes values.
 ///
 /// This module is intended to be used through the Serde `with` attribute. Use
-/// [`serde_avro_bytes`](crate::serde_avro_bytes) for non optional bytes.
+/// [`avro_bytes`] for non optional bytes.
 ///
-/// See usage with below example:
 /// ```rust
-/// use apache_avro::{serde_avro_bytes_opt, serde_avro_fixed_opt};
+/// use apache_avro::serde::serde_with::{avro_bytes_opt, avro_fixed_opt};
 /// use serde::{Deserialize, Serialize};
 ///
 /// #[derive(Serialize, Deserialize)]
 /// struct StructWithBytes {
-///     #[serde(with = "serde_avro_bytes_opt")]
+///     #[serde(with = "avro_bytes_opt")]
 ///     vec_field: Option<Vec<u8>>,
 ///
-///     #[serde(with = "serde_avro_fixed_opt")]
+///     #[serde(with = "avro_fixed_opt")]
 ///     fixed_field: Option<[u8; 6]>,
 /// }
 /// ```
-pub mod serde_avro_bytes_opt {
+pub mod avro_bytes_opt {
     use serde::{Deserializer, Serializer};
     use std::borrow::Borrow;
 
@@ -116,23 +114,22 @@ pub mod serde_avro_bytes_opt {
 /// Efficient (de)serialization of Avro fixed values.
 ///
 /// This module is intended to be used through the Serde `with` attribute. Use
-/// [`serde_avro_fixed_opt`](crate::serde_avro_fixed_opt) for optional fixed 
values.
+/// [`avro_fixed_opt`] for optional fixed values.
 ///
-/// See usage with below example:
 /// ```rust
-/// use apache_avro::{serde_avro_bytes, serde_avro_fixed};
+/// use apache_avro::serde::serde_with::{avro_bytes, avro_fixed};
 /// use serde::{Deserialize, Serialize};
 ///
 /// #[derive(Serialize, Deserialize)]
 /// struct StructWithBytes {
-///     #[serde(with = "serde_avro_bytes")]
+///     #[serde(with = "avro_bytes")]
 ///     vec_field: Vec<u8>,
 ///
-///     #[serde(with = "serde_avro_fixed")]
+///     #[serde(with = "avro_fixed")]
 ///     fixed_field: [u8; 6],
 /// }
 /// ```
-pub mod serde_avro_fixed {
+pub mod avro_fixed {
     use super::{BytesType, SER_BYTES_TYPE};
     use serde::{Deserializer, Serializer};
 
@@ -157,23 +154,22 @@ pub mod serde_avro_fixed {
 /// Efficient (de)serialization of optional Avro fixed values.
 ///
 /// This module is intended to be used through the Serde `with` attribute. Use
-/// [`serde_avro_fixed`](crate::serde_avro_fixed) for non optional fixed 
values.
+/// [`avro_fixed`] for non optional fixed values.
 ///
-/// See usage with below example:
 /// ```rust
-/// use apache_avro::{serde_avro_bytes_opt, serde_avro_fixed_opt};
+/// use apache_avro::serde::serde_with::{avro_bytes_opt, avro_fixed_opt};
 /// use serde::{Deserialize, Serialize};
 ///
 /// #[derive(Serialize, Deserialize)]
 /// struct StructWithBytes {
-///     #[serde(with = "serde_avro_bytes_opt")]
+///     #[serde(with = "avro_bytes_opt")]
 ///     vec_field: Option<Vec<u8>>,
 ///
-///     #[serde(with = "serde_avro_fixed_opt")]
+///     #[serde(with = "avro_fixed_opt")]
 ///     fixed_field: Option<[u8; 6]>,
 /// }
 /// ```
-pub mod serde_avro_fixed_opt {
+pub mod avro_fixed_opt {
     use super::{BytesType, SER_BYTES_TYPE};
     use serde::{Deserializer, Serializer};
     use std::borrow::Borrow;
@@ -199,26 +195,27 @@ pub mod serde_avro_fixed_opt {
 
 /// Efficient (de)serialization of Avro bytes/fixed borrowed values.
 ///
-/// This module is intended to be used through the Serde `with` attribute. 
Note that
-/// `bytes: &[u8]` are always serialized as
-/// [`Value::Bytes`](crate::types::Value::Bytes). However, both
-/// [`Value::Bytes`](crate::types::Value::Bytes) and
-/// [`Value::Fixed`](crate::types::Value::Fixed) can be deserialized as `bytes:
-/// &[u8]`. Use [`serde_avro_slice_opt`](crate::serde_avro_slice_opt) for 
optional
-/// bytes/fixed borrowed values.
+/// This module is intended to be used through the Serde `with` attribute.
+///
+/// Note that `&[u8]` are always serialized as [`Value::Bytes`]. However,
+/// both [`Value::Bytes`] and [`Value::Fixed`] can be deserialized as `&[u8]`.
+///
+/// Use [`avro_slice_opt`] for optional bytes/fixed borrowed values.
 ///
-/// See usage with below example:
 /// ```rust
-/// use apache_avro::serde_avro_slice;
+/// use apache_avro::serde::serde_with::avro_slice;
 /// use serde::{Deserialize, Serialize};
 ///
 /// #[derive(Serialize, Deserialize)]
 /// struct StructWithBytes<'a> {
-///     #[serde(with = "serde_avro_slice")]
+///     #[serde(with = "avro_slice")]
 ///     slice_field: &'a [u8],
 /// }
 /// ```
-pub mod serde_avro_slice {
+///
+/// [`Value::Bytes`]: crate::types::Value::Bytes
+/// [`Value::Fixed`]: crate::types::Value::Fixed
+pub mod avro_slice {
     use super::DE_BYTES_BORROWED;
     use serde::{Deserializer, Serializer};
 
@@ -242,26 +239,28 @@ pub mod serde_avro_slice {
 
 /// Efficient (de)serialization of optional Avro bytes/fixed borrowed values.
 ///
-/// This module is intended to be used through the Serde `with` attribute. 
Note that
-/// `bytes: &[u8]` are always serialized as
-/// [`Value::Bytes`](crate::types::Value::Bytes). However, both
-/// [`Value::Bytes`](crate::types::Value::Bytes) and
-/// [`Value::Fixed`](crate::types::Value::Fixed) can be deserialized as `bytes:
-/// &[u8]`. Use [`serde_avro_slice`](crate::serde_avro_slice) for non optional
-/// bytes/fixed borrowed values.
+/// This module is intended to be used through the Serde `with` attribute.
+///
+/// Note that `&[u8]` are always serialized as [`Value::Bytes`]. However,
+/// both [`Value::Bytes`] and [`Value::Fixed`] can be deserialized as `&[u8]`.
+///
+/// Use [`avro_slice`] for non optional bytes/fixed borrowed values.
 ///
 /// See usage with below example:
 /// ```rust
-/// use apache_avro::serde_avro_slice_opt;
+/// use apache_avro::serde::serde_with::avro_slice_opt;
 /// use serde::{Deserialize, Serialize};
 ///
 /// #[derive(Serialize, Deserialize)]
 /// struct StructWithBytes<'a> {
-///     #[serde(with = "serde_avro_slice_opt")]
+///     #[serde(with = "avro_slice_opt")]
 ///     slice_field: Option<&'a [u8]>,
 /// }
 /// ```
-pub mod serde_avro_slice_opt {
+///
+/// [`Value::Bytes`]: crate::types::Value::Bytes
+/// [`Value::Fixed`]: crate::types::Value::Fixed
+pub mod avro_slice_opt {
     use super::DE_BYTES_BORROWED;
     use serde::{Deserializer, Serializer};
     use std::borrow::Borrow;
@@ -295,19 +294,19 @@ mod tests {
     fn avro_3631_validate_schema_for_struct_with_byte_types() {
         #[derive(Debug, Serialize)]
         struct TestStructWithBytes<'a> {
-            #[serde(with = "serde_avro_bytes")]
+            #[serde(with = "avro_bytes")]
             vec_field: Vec<u8>,
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             vec_field_opt: Option<Vec<u8>>,
 
-            #[serde(with = "serde_avro_fixed")]
+            #[serde(with = "avro_fixed")]
             fixed_field: [u8; 6],
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             fixed_field_opt: Option<[u8; 7]>,
 
-            #[serde(with = "serde_avro_slice")]
+            #[serde(with = "avro_slice")]
             slice_field: &'a [u8],
-            #[serde(with = "serde_avro_slice_opt")]
+            #[serde(with = "avro_slice_opt")]
             slice_field_opt: Option<&'a [u8]>,
         }
 
@@ -362,32 +361,32 @@ mod tests {
     fn avro_3631_deserialize_value_to_struct_with_byte_types() {
         #[derive(Debug, Deserialize, PartialEq)]
         struct TestStructWithBytes<'a> {
-            #[serde(with = "serde_avro_bytes")]
+            #[serde(with = "avro_bytes")]
             vec_field: Vec<u8>,
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             vec_field_opt: Option<Vec<u8>>,
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             vec_field_opt2: Option<Vec<u8>>,
 
-            #[serde(with = "serde_avro_fixed")]
+            #[serde(with = "avro_fixed")]
             fixed_field: [u8; 6],
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             fixed_field_opt: Option<[u8; 7]>,
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             fixed_field_opt2: Option<[u8; 8]>,
 
-            #[serde(with = "serde_avro_slice")]
+            #[serde(with = "avro_slice")]
             slice_bytes_field: &'a [u8],
-            #[serde(with = "serde_avro_slice_opt")]
+            #[serde(with = "avro_slice_opt")]
             slice_bytes_field_opt: Option<&'a [u8]>,
-            #[serde(with = "serde_avro_slice_opt")]
+            #[serde(with = "avro_slice_opt")]
             slice_bytes_field_opt2: Option<&'a [u8]>,
 
-            #[serde(with = "serde_avro_slice")]
+            #[serde(with = "avro_slice")]
             slice_fixed_field: &'a [u8],
-            #[serde(with = "serde_avro_slice_opt")]
+            #[serde(with = "avro_slice_opt")]
             slice_fixed_field_opt: Option<&'a [u8]>,
-            #[serde(with = "serde_avro_slice_opt")]
+            #[serde(with = "avro_slice_opt")]
             slice_fixed_field_opt2: Option<&'a [u8]>,
         }
 
@@ -491,46 +490,46 @@ mod tests {
             array_field: &'a [u8],
             vec_field: Vec<u8>,
 
-            #[serde(with = "serde_avro_fixed")]
+            #[serde(with = "avro_fixed")]
             vec_field2: Vec<u8>,
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             vec_field2_opt: Option<Vec<u8>>,
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             vec_field2_opt2: Option<Vec<u8>>,
 
-            #[serde(with = "serde_avro_bytes")]
+            #[serde(with = "avro_bytes")]
             vec_field3: Vec<u8>,
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             vec_field3_opt: Option<Vec<u8>>,
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             vec_field3_opt2: Option<Vec<u8>>,
 
-            #[serde(with = "serde_avro_fixed")]
+            #[serde(with = "avro_fixed")]
             fixed_field: [u8; 6],
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             fixed_field_opt: Option<[u8; 5]>,
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             fixed_field_opt2: Option<[u8; 4]>,
 
-            #[serde(with = "serde_avro_fixed")]
+            #[serde(with = "avro_fixed")]
             fixed_field2: &'a [u8],
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             fixed_field2_opt: Option<&'a [u8]>,
-            #[serde(with = "serde_avro_fixed_opt")]
+            #[serde(with = "avro_fixed_opt")]
             fixed_field2_opt2: Option<&'a [u8]>,
 
-            #[serde(with = "serde_avro_bytes")]
+            #[serde(with = "avro_bytes")]
             bytes_field: &'a [u8],
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             bytes_field_opt: Option<&'a [u8]>,
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             bytes_field_opt2: Option<&'a [u8]>,
 
-            #[serde(with = "serde_avro_bytes")]
+            #[serde(with = "avro_bytes")]
             bytes_field2: [u8; 6],
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             bytes_field2_opt: Option<[u8; 7]>,
-            #[serde(with = "serde_avro_bytes_opt")]
+            #[serde(with = "avro_bytes_opt")]
             bytes_field2_opt2: Option<[u8; 8]>,
         }
 
diff --git a/avro/src/types.rs b/avro/src/types.rs
index 4c659c5..7059887 100644
--- a/avro/src/types.rs
+++ b/avro/src/types.rs
@@ -2809,7 +2809,7 @@ Field with name '"b"' is not a member of the map items"#,
 
     #[test]
     fn test_avro_3460_validation_with_refs_real_struct() -> TestResult {
-        use crate::serde::ser::Serializer;
+        use crate::serde::to_value;
         use serde::Serialize;
 
         #[derive(Serialize, Clone)]
@@ -2874,12 +2874,9 @@ Field with name '"b"' is not a member of the map items"#,
             b: None,
         };
 
-        let mut ser = Serializer::default();
-        let test_outer1: Value = test_outer1.serialize(&mut ser)?;
-        let mut ser = Serializer::default();
-        let test_outer2: Value = test_outer2.serialize(&mut ser)?;
-        let mut ser = Serializer::default();
-        let test_outer3: Value = test_outer3.serialize(&mut ser)?;
+        let test_outer1 = to_value(test_outer1)?;
+        let test_outer2 = to_value(test_outer2)?;
+        let test_outer3 = to_value(test_outer3)?;
 
         assert!(
             !test_outer1.validate(&schema),
@@ -2898,7 +2895,7 @@ Field with name '"b"' is not a member of the map items"#,
     }
 
     fn avro_3674_with_or_without_namespace(with_namespace: bool) -> TestResult 
{
-        use crate::serde::ser::Serializer;
+        use crate::serde::to_value;
         use serde::Serialize;
 
         let schema_str = r#"
@@ -2969,8 +2966,7 @@ Field with name '"b"' is not a member of the map items"#,
             },
         };
 
-        let mut ser = Serializer::default();
-        let test_value: Value = msg.serialize(&mut ser)?;
+        let test_value = to_value(msg)?;
         assert!(test_value.validate(&schema), "test_value should validate");
         assert!(
             test_value.resolve(&schema).is_ok(),
@@ -2991,7 +2987,7 @@ Field with name '"b"' is not a member of the map items"#,
     }
 
     fn avro_3688_schema_resolution_panic(set_field_b: bool) -> TestResult {
-        use crate::serde::ser::Serializer;
+        use crate::serde::to_value;
         use serde::{Deserialize, Serialize};
 
         let schema_str = r#"{
@@ -3052,8 +3048,7 @@ Field with name '"b"' is not a member of the map items"#,
             },
         };
 
-        let mut ser = Serializer::default();
-        let test_value: Value = msg.serialize(&mut ser)?;
+        let test_value = to_value(msg)?;
         assert!(test_value.validate(&schema), "test_value should validate");
         assert!(
             test_value.resolve(&schema).is_ok(),
diff --git a/avro/src/writer.rs b/avro/src/writer.rs
index 1c375d9..b17e0dd 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, SchemaAwareWriteSerializer},
     types::Value,
 };
 use serde::Serialize;
diff --git a/avro/tests/avro-rs-285-bytes_deserialization.rs 
b/avro/tests/avro-rs-285-bytes_deserialization.rs
index 5ac2688..1e9531b 100644
--- a/avro/tests/avro-rs-285-bytes_deserialization.rs
+++ b/avro/tests/avro-rs-285-bytes_deserialization.rs
@@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Deserialize, PartialEq, Serialize)]
 struct ExampleByteArray {
-    #[serde(with = "apache_avro::serde_avro_bytes_opt")]
+    #[serde(with = "apache_avro::serde::avro_bytes_opt")]
     data_bytes: Option<Vec<u8>>,
     description: Option<String>,
 }
diff --git a/avro_derive/src/lib.rs b/avro_derive/src/lib.rs
index 8723593..94843a2 100644
--- a/avro_derive/src/lib.rs
+++ b/avro_derive/src/lib.rs
@@ -17,6 +17,14 @@
 
 #![cfg_attr(nightly, feature(proc_macro_diagnostic))]
 
+//! This crate provides the `AvroSchema` derive macro.
+//! ```no_run
+//! #[derive(AvroSchema)]
+//! ```
+//! Please see the documentation of the [`AvroSchema`] trait for instructions 
on how to use it.
+//!
+//! [`AvroSchema`]: 
https://docs.rs/apache-avro/latest/apache_avro/schema/trait.AvroSchema.html
+
 mod attributes;
 mod case;
 
@@ -84,7 +92,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::serde::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 +346,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::serde::AvroSchemaComponent>::get_schema_in_ctxt()`
+/// - `A<T> -> <A<T> as 
apache_avro::serde::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::serde::AvroSchemaComponent>::get_schema_in_ctxt(named_schemas, 
enclosing_namespace)}
 }
 
 /// Stolen from serde
@@ -496,7 +504,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::serde::AvroSchemaComponent for Basic {
                         fn get_schema_in_ctxt(
                             named_schemas: &mut std::collections::HashMap<
                                 apache_avro::schema::Name,
@@ -640,9 +648,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::serde::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::serde::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::serde::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..2174235 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},
+    serde::{AvroSchema, AvroSchemaComponent},
 };
 use apache_avro_derive::*;
 use proptest::prelude::*;

Reply via email to