This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/avro-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 84ee8e4 feat: Use builder pattern for creating RecordSchema,
EnumSchema, FixedSchema and RecordField (#108)
84ee8e4 is described below
commit 84ee8e4ef3729dff30d14a4cf53e7489c885188f
Author: Martin Grigorov <[email protected]>
AuthorDate: Tue Jan 21 10:48:54 2025 +0200
feat: Use builder pattern for creating RecordSchema, EnumSchema,
FixedSchema and RecordField (#108)
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 8bbe522..d264b36 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 9eeec17..3f19f9c 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.1", 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 1737665..8f14b79 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>,
}
@@ -2709,12 +2722,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 {
@@ -2722,24 +2732,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(())
@@ -2781,30 +2787,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(())
@@ -3447,17 +3446,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],