tatara-rust-composite — L2 composition primitive.
CompositeDeriveSpec bundles N inner derive Specs (any kind) under
one user-facing #[derive(<name>)]. The emitted proc-macro
crate dispatches the consumer's DeriveInput to each inner Spec's
own emitter and concatenates the produced TokenStreams.
Authoring shape:
use tatara_rust_ast::{CompileToCrate, Ident};
use tatara_rust_derive::{PerFieldDeriveSpec, PerFieldTarget};
use tatara_rust_composite::{CompositeDeriveSpec, CompositeMember};
let getter = PerFieldDeriveSpec {
trait_name: Ident::new("AccessorGetter"),
target: PerFieldTarget::NamedStruct,
trait_ref: None,
per_field_template:
"pub fn #field_name(&self) -> &#field_ty { &self.#field_name }".into(),
method_name_template: None,
impl_prelude: None,
skip_fields: vec![],
field_attribute: None,
};
let setter = PerFieldDeriveSpec {
trait_name: Ident::new("AccessorSetter"),
target: PerFieldTarget::NamedStruct,
trait_ref: None,
per_field_template:
"pub fn #method_ident(&mut self, v: #field_ty) { self.#field_name = v; }".into(),
method_name_template: Some("set_{}".into()),
impl_prelude: None,
skip_fields: vec![],
field_attribute: None,
};
let bundle = CompositeDeriveSpec {
bundle_name: Ident::new("Accessor"),
members: vec![
CompositeMember::PerField(getter),
CompositeMember::PerField(setter),
],
};
let scaffold = bundle.compile_to_crate("accessor-derive").unwrap();
assert!(scaffold.to_files().contains_key("src/lib.rs"));