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

mgrigorov pushed a commit to branch more-builder-with-bon
in repository https://gitbox.apache.org/repos/asf/avro-rs.git

commit 1a228019fb1069da17df9b2dc75b04357716836c
Author: Martin Tzvetanov Grigorov <[email protected]>
AuthorDate: Mon Jan 20 11:42:40 2025 +0200

    feat: Use builder pattern for creating RecordSchema, EnumSchema, 
FixedSchema and RecordField
    
    Replace typed-builder with bon (https://bon-rs.com) because it provides
    more features, e.g. named parameters via Function Builder
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
---
 Cargo.lock         |  64 +++++++++++++++++++----------
 avro/Cargo.toml    |   2 +-
 avro/src/decode.rs |  14 +++----
 avro/src/schema.rs | 118 ++++++++++++++++++++++++++---------------------------
 avro/src/writer.rs |  10 ++---
 5 files changed, 113 insertions(+), 95 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 605ae3e..e570099 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -76,6 +76,7 @@ dependencies = [
  "apache-avro-derive",
  "apache-avro-test-helper",
  "bigdecimal",
+ "bon",
  "bzip2",
  "crc32fast",
  "criterion",
@@ -100,7 +101,6 @@ dependencies = [
  "strum",
  "strum_macros",
  "thiserror",
- "typed-builder",
  "uuid",
  "xz2",
  "zstd",
@@ -191,6 +191,31 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "bon"
+version = "3.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "fe7acc34ff59877422326db7d6f2d845a582b16396b6b08194942bf34c6528ab"
+dependencies = [
+ "bon-macros",
+ "rustversion",
+]
+
+[[package]]
+name = "bon-macros"
+version = "3.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "4159dd617a7fbc9be6a692fe69dc2954f8e6bb6bb5e4d7578467441390d77fd0"
+dependencies = [
+ "darling",
+ "ident_case",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
 [[package]]
 name = "bumpalo"
 version = "3.16.0"
@@ -428,6 +453,7 @@ dependencies = [
  "ident_case",
  "proc-macro2",
  "quote",
+ "strsim",
  "syn",
 ]
 
@@ -931,6 +957,16 @@ dependencies = [
  "yansi",
 ]
 
+[[package]]
+name = "prettyplease"
+version = "0.2.29"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.93"
@@ -1260,6 +1296,12 @@ version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b"
 
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
 [[package]]
 name = "strum"
 version = "0.26.3"
@@ -1320,26 +1362,6 @@ dependencies = [
  "serde_json",
 ]
 
-[[package]]
-name = "typed-builder"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7e14ed59dc8b7b26cacb2a92bad2e8b1f098806063898ab42a3bd121d7d45e75"
-dependencies = [
- "typed-builder-macro",
-]
-
-[[package]]
-name = "typed-builder-macro"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "560b82d656506509d43abe30e0ba64c56b1953ab3d4fe7ba5902747a7a3cedd5"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
 [[package]]
 name = "typenum"
 version = "1.17.0"
diff --git a/avro/Cargo.toml b/avro/Cargo.toml
index 8e513ce..d7b0e8f 100644
--- a/avro/Cargo.toml
+++ b/avro/Cargo.toml
@@ -55,6 +55,7 @@ name = "single"
 [dependencies]
 apache-avro-derive = { default-features = false, version = "0.18.0", path = 
"../avro_derive", optional = true }
 bigdecimal = { default-features = false, version = "0.4.7", features = ["std", 
"serde"] }
+bon = { default-features = false, version = "3.3.2" }
 bzip2 = { version = "0.5.0", optional = true }
 crc32fast = { default-features = false, version = "1.4.2", optional = true }
 digest = { default-features = false, version = "0.10.7", features = 
["core-api"] }
@@ -69,7 +70,6 @@ snap = { default-features = false, version = "1.1.0", 
optional = true }
 strum = { default-features = false, version = "0.26.3" }
 strum_macros = { default-features = false, version = "0.26.4" }
 thiserror = { default-features = false, version = "2.0.11" }
-typed-builder = { default-features = false, version = "0.20.0" }
 uuid = { default-features = false, version = "1.12.0", features = ["serde", 
"std"] }
 xz2 = { default-features = false, version = "0.1.7", optional = true }
 zstd = { default-features = false, version = "0.13.2", optional = true }
diff --git a/avro/src/decode.rs b/avro/src/decode.rs
index 46e3381..7f5737d 100644
--- a/avro/src/decode.rs
+++ b/avro/src/decode.rs
@@ -415,14 +415,12 @@ mod tests {
     fn test_negative_decimal_value() -> TestResult {
         use crate::{encode::encode, schema::Name};
         use num_bigint::ToBigInt;
-        let inner = Box::new(Schema::Fixed(FixedSchema {
-            size: 2,
-            doc: None,
-            name: Name::new("decimal")?,
-            aliases: None,
-            default: None,
-            attributes: Default::default(),
-        }));
+        let inner = Box::new(Schema::Fixed(
+            FixedSchema::builder()
+                .name(Name::new("decimal")?)
+                .size(2)
+                .build(),
+        ));
         let schema = Schema::Decimal(DecimalSchema {
             inner,
             precision: 4,
diff --git a/avro/src/schema.rs b/avro/src/schema.rs
index 93dbe18..13fc905 100644
--- a/avro/src/schema.rs
+++ b/avro/src/schema.rs
@@ -623,11 +623,12 @@ pub(crate) fn resolve_names_with_schemata(
 }
 
 /// Represents a `field` in a `record` Avro schema.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(bon::Builder, Clone, Debug, PartialEq)]
 pub struct RecordField {
     /// Name of the field.
     pub name: String,
     /// Documentation of the field.
+    #[builder(default)]
     pub doc: Documentation,
     /// Aliases of the field's name. They have no namespace.
     pub aliases: Option<Vec<String>>,
@@ -640,10 +641,13 @@ pub struct RecordField {
     /// Order of the field.
     ///
     /// **NOTE** This currently has no effect.
+    #[builder(default = RecordFieldOrder::Ignore)]
     pub order: RecordFieldOrder,
     /// Position of the field in the list of `field` of its parent `Schema`
+    #[builder(default)]
     pub position: usize,
     /// A collection of all unknown fields in the record field.
+    #[builder(default = BTreeMap::new())]
     pub custom_attributes: BTreeMap<String, Value>,
 }
 
@@ -788,13 +792,15 @@ impl RecordField {
 }
 
 /// A description of an Enum schema.
-#[derive(Debug, Clone)]
+#[derive(bon::Builder, Debug, Clone)]
 pub struct RecordSchema {
     /// The name of the schema
     pub name: Name,
     /// The aliases of the schema
+    #[builder(default)]
     pub aliases: Aliases,
     /// The documentation of the schema
+    #[builder(default)]
     pub doc: Documentation,
     /// The set of fields of the schema
     pub fields: Vec<RecordField>,
@@ -802,40 +808,47 @@ pub struct RecordSchema {
     /// of `fields`.
     pub lookup: BTreeMap<String, usize>,
     /// The custom attributes of the schema
+    #[builder(default = BTreeMap::new())]
     pub attributes: BTreeMap<String, Value>,
 }
 
 /// A description of an Enum schema.
-#[derive(Debug, Clone)]
+#[derive(bon::Builder, Debug, Clone)]
 pub struct EnumSchema {
     /// The name of the schema
     pub name: Name,
     /// The aliases of the schema
+    #[builder(default)]
     pub aliases: Aliases,
     /// The documentation of the schema
+    #[builder(default)]
     pub doc: Documentation,
     /// The set of symbols of the schema
     pub symbols: Vec<String>,
     /// An optional default symbol used for compatibility
     pub default: Option<String>,
     /// The custom attributes of the schema
+    #[builder(default = BTreeMap::new())]
     pub attributes: BTreeMap<String, Value>,
 }
 
 /// A description of a Union schema.
-#[derive(Debug, Clone)]
+#[derive(bon::Builder, Debug, Clone)]
 pub struct FixedSchema {
     /// The name of the schema
     pub name: Name,
     /// The aliases of the schema
+    #[builder(default)]
     pub aliases: Aliases,
     /// The documentation of the schema
+    #[builder(default)]
     pub doc: Documentation,
     /// The size of the fixed schema
     pub size: usize,
     /// An optional default symbol used for compatibility
     pub default: Option<String>,
     /// The custom attributes of the schema
+    #[builder(default = BTreeMap::new())]
     pub attributes: BTreeMap<String, Value>,
 }
 
@@ -2644,12 +2657,9 @@ mod tests {
 
     #[test]
     fn test_avro_3621_nullable_record_field() -> TestResult {
-        let nullable_record_field = RecordField {
-            name: "next".to_string(),
-            doc: None,
-            default: None,
-            aliases: None,
-            schema: Schema::Union(UnionSchema::new(vec![
+        let nullable_record_field = RecordField::builder()
+            .name("next".to_string())
+            .schema(Schema::Union(UnionSchema::new(vec![
                 Schema::Null,
                 Schema::Ref {
                     name: Name {
@@ -2657,24 +2667,20 @@ mod tests {
                         namespace: None,
                     },
                 },
-            ])?),
-            order: RecordFieldOrder::Ascending,
-            position: 1,
-            custom_attributes: Default::default(),
-        };
+            ])?))
+            .order(RecordFieldOrder::Ascending)
+            .position(1)
+            .build();
 
         assert!(nullable_record_field.is_nullable());
 
-        let non_nullable_record_field = RecordField {
-            name: "next".to_string(),
-            doc: None,
-            default: Some(json!(2)),
-            aliases: None,
-            schema: Schema::Long,
-            order: RecordFieldOrder::Ascending,
-            position: 1,
-            custom_attributes: Default::default(),
-        };
+        let non_nullable_record_field = RecordField::builder()
+            .name("next".to_string())
+            .default(json!(2))
+            .schema(Schema::Long)
+            .order(RecordFieldOrder::Ascending)
+            .position(1)
+            .build();
 
         assert!(!non_nullable_record_field.is_nullable());
         Ok(())
@@ -2716,30 +2722,23 @@ mod tests {
             .unwrap()
             .clone();
 
-        let schema_c_expected = Schema::Record(RecordSchema {
-            name: Name::new("C")?,
-            aliases: None,
-            doc: None,
-            fields: vec![RecordField {
-                name: "field_one".to_string(),
-                doc: None,
-                default: None,
-                aliases: None,
-                schema: Schema::Union(UnionSchema::new(vec![
-                    Schema::Ref {
-                        name: Name::new("A")?,
-                    },
-                    Schema::Ref {
-                        name: Name::new("B")?,
-                    },
-                ])?),
-                order: RecordFieldOrder::Ignore,
-                position: 0,
-                custom_attributes: Default::default(),
-            }],
-            lookup: BTreeMap::from_iter(vec![("field_one".to_string(), 0)]),
-            attributes: Default::default(),
-        });
+        let schema_c_expected = Schema::Record(
+            RecordSchema::builder()
+                .name(Name::new("C")?)
+                .fields(vec![RecordField::builder()
+                    .name("field_one".to_string())
+                    .schema(Schema::Union(UnionSchema::new(vec![
+                        Schema::Ref {
+                            name: Name::new("A")?,
+                        },
+                        Schema::Ref {
+                            name: Name::new("B")?,
+                        },
+                    ])?))
+                    .build()])
+                .lookup(BTreeMap::from_iter(vec![("field_one".to_string(), 
0)]))
+                .build(),
+        );
 
         assert_eq!(schema_c, schema_c_expected);
         Ok(())
@@ -3382,17 +3381,16 @@ mod tests {
                     doc: None,
                     default: None,
                     aliases: None,
-                    schema: Schema::Enum(EnumSchema {
-                        name: Name {
-                            name: "enum".to_owned(),
-                            namespace: None,
-                        },
-                        aliases: None,
-                        doc: None,
-                        symbols: vec!["one".to_string(), "two".to_string(), 
"three".to_string()],
-                        default: None,
-                        attributes: Default::default(),
-                    }),
+                    schema: Schema::Enum(
+                        EnumSchema::builder()
+                            .name(Name::new("enum")?)
+                            .symbols(vec![
+                                "one".to_string(),
+                                "two".to_string(),
+                                "three".to_string(),
+                            ])
+                            .build(),
+                    ),
                     order: RecordFieldOrder::Ascending,
                     position: 0,
                     custom_attributes: Default::default(),
diff --git a/avro/src/writer.rs b/avro/src/writer.rs
index f1fdae4..0f824b3 100644
--- a/avro/src/writer.rs
+++ b/avro/src/writer.rs
@@ -31,21 +31,21 @@ const DEFAULT_BLOCK_SIZE: usize = 16000;
 const AVRO_OBJECT_HEADER: &[u8] = b"Obj\x01";
 
 /// Main interface for writing Avro formatted values.
-#[derive(typed_builder::TypedBuilder)]
+#[derive(bon::Builder)]
 pub struct Writer<'a, W> {
     schema: &'a Schema,
     writer: W,
-    #[builder(default, setter(skip))]
+    #[builder(skip)]
     resolved_schema: Option<ResolvedSchema<'a>>,
     #[builder(default = Codec::Null)]
     codec: Codec,
     #[builder(default = DEFAULT_BLOCK_SIZE)]
     block_size: usize,
-    #[builder(default = Vec::with_capacity(block_size), setter(skip))]
+    #[builder(skip = Vec::with_capacity(block_size))]
     buffer: Vec<u8>,
-    #[builder(default, setter(skip))]
+    #[builder(skip)]
     serializer: Serializer,
-    #[builder(default = 0, setter(skip))]
+    #[builder(skip)]
     num_values: usize,
     #[builder(default = generate_sync_marker())]
     marker: [u8; 16],

Reply via email to