diff --git a/README.md b/README.md index c2f37e5..29dec78 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Options: --chrono-dates Use chrono::NaiveDateTime for date/timestamps logical types --derive-builders Derive builders for generated record structs --derive-schemas Derive AvroSchema for generated record structs + --extra_derives Append extra derive macros list to the generated record structs -h, --help Print help -V, --version Print version ``` diff --git a/src/gen.rs b/src/gen.rs index 01c70dc..65f7a59 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -285,6 +285,7 @@ pub struct GeneratorBuilder { use_chrono_dates: bool, derive_builders: bool, derive_schemas: bool, + extra_derives: Vec, } impl Default for GeneratorBuilder { @@ -296,6 +297,7 @@ impl Default for GeneratorBuilder { use_chrono_dates: false, derive_builders: false, derive_schemas: false, + extra_derives: vec![], } } } @@ -351,6 +353,14 @@ impl GeneratorBuilder { self } + /// Adds support to derive custom macros. + /// + /// Applies to record structs. + pub fn extra_derives(mut self, extra_derives: Vec) -> GeneratorBuilder { + self.extra_derives = extra_derives; + self + } + /// Create a [`Generator`](Generator) with the builder parameters. pub fn build(self) -> Result { let mut templater = Templater::new()?; @@ -360,6 +370,7 @@ impl GeneratorBuilder { templater.use_chrono_dates = self.use_chrono_dates; templater.derive_builders = self.derive_builders; templater.derive_schemas = self.derive_schemas; + templater.extra_derives = self.extra_derives; Ok(Generator { templater }) } } diff --git a/src/main.rs b/src/main.rs index 1283c69..7400d2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,10 @@ struct Args { /// Derive AvroSchema for generated record structs #[clap(long)] pub derive_schemas: bool, + + /// Extract Derives for generated record structs, comma separated, e.g. `std::fmt::Display,std::string::ToString` + #[clap(long, value_delimiter = ',')] + pub extra_derives: Vec, } fn run() -> Result<(), Box> { @@ -70,6 +74,7 @@ fn run() -> Result<(), Box> { .use_chrono_dates(args.chrono_dates) .derive_builders(args.derive_builders) .derive_schemas(args.derive_schemas) + .extra_derives(args.extra_derives) .build()?; g.gen(&source, &mut out)?; diff --git a/src/templates.rs b/src/templates.rs index 7861269..998f745 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -25,7 +25,7 @@ pub const RECORD_TEMPLATE: &str = r#" /// {{ doc_line }} {%- endfor %} {%- endif %} -#[derive(Debug, PartialEq{%- if is_eq_derivable %}, Eq{%- endif %}, Clone, serde::Deserialize, serde::Serialize{%- if derive_builders %}, derive_builder::Builder {%- endif %}{%- if derive_schemas %}, apache_avro::AvroSchema {%- endif %})] +#[derive(Debug, PartialEq{%- if is_eq_derivable %}, Eq{%- endif %}, Clone, serde::Deserialize, serde::Serialize{%- if derive_builders %}, derive_builder::Builder {%- endif %}{%- if derive_schemas %}, apache_avro::AvroSchema {%- endif %} {%- if extra_derives %}, {{ extra_derives}} {%- endif %})] {%- if derive_builders %} #[builder(setter(into))] {%- endif %} @@ -509,6 +509,7 @@ pub struct Templater { pub use_chrono_dates: bool, pub derive_builders: bool, pub derive_schemas: bool, + pub extra_derives: Vec, } impl Templater { @@ -530,6 +531,7 @@ impl Templater { use_chrono_dates: false, derive_builders: false, derive_schemas: false, + extra_derives: vec![], }) } @@ -599,6 +601,9 @@ impl Templater { ctx.insert("doc", doc); ctx.insert("derive_builders", &self.derive_builders); ctx.insert("derive_schemas", &self.derive_schemas); + if !self.extra_derives.is_empty() { + ctx.insert("extra_derives", &self.extra_derives.join(", ")); + } let mut f = Vec::new(); // field names; let mut t = HashMap::new(); // field name -> field type diff --git a/tests/generation.rs b/tests/generation.rs index 87f6e0b..3cacc86 100644 --- a/tests/generation.rs +++ b/tests/generation.rs @@ -230,3 +230,28 @@ fn gen_recursive() { fn gen_interop() { validate_generation("interop", Generator::new().unwrap()); } + +#[test] +fn gen_one_extra_derives() { + validate_generation( + "one_extra_derive", + Generator::builder() + .extra_derives(vec!["std::fmt::Display".to_string()]) + .build() + .unwrap(), + ); +} + +#[test] +fn gen_two_extra_derives() { + validate_generation( + "two_extra_derives", + Generator::builder() + .extra_derives(vec![ + "std::fmt::Display".to_string(), + "std::string::ToString".to_string(), + ]) + .build() + .unwrap(), + ); +} diff --git a/tests/schemas/one_extra_derive.avsc b/tests/schemas/one_extra_derive.avsc new file mode 100644 index 0000000..133fb5c --- /dev/null +++ b/tests/schemas/one_extra_derive.avsc @@ -0,0 +1,8 @@ +{ + "type": "record", + "name": "test", + "fields": [ + {"name": "a", "type": "long", "default": 42}, + {"name": "b", "type": "string"} + ] +} diff --git a/tests/schemas/one_extra_derive.rs b/tests/schemas/one_extra_derive.rs new file mode 100644 index 0000000..40a0aa4 --- /dev/null +++ b/tests/schemas/one_extra_derive.rs @@ -0,0 +1,10 @@ + +#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize, std::fmt::Display)] +pub struct Test { + #[serde(default = "default_test_a")] + pub a: i64, + pub b: String, +} + +#[inline(always)] +fn default_test_a() -> i64 { 42 } diff --git a/tests/schemas/two_extra_derives.avsc b/tests/schemas/two_extra_derives.avsc new file mode 100644 index 0000000..133fb5c --- /dev/null +++ b/tests/schemas/two_extra_derives.avsc @@ -0,0 +1,8 @@ +{ + "type": "record", + "name": "test", + "fields": [ + {"name": "a", "type": "long", "default": 42}, + {"name": "b", "type": "string"} + ] +} diff --git a/tests/schemas/two_extra_derives.rs b/tests/schemas/two_extra_derives.rs new file mode 100644 index 0000000..612998c --- /dev/null +++ b/tests/schemas/two_extra_derives.rs @@ -0,0 +1,10 @@ + +#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize, std::fmt::Display, std::string::ToString)] +pub struct Test { + #[serde(default = "default_test_a")] + pub a: i64, + pub b: String, +} + +#[inline(always)] +fn default_test_a() -> i64 { 42 }