diff --git a/confik-macros/src/lib.rs b/confik-macros/src/lib.rs index 02047a4..02b821e 100644 --- a/confik-macros/src/lib.rs +++ b/confik-macros/src/lib.rs @@ -330,6 +330,9 @@ struct FieldImplementer { /// The field type. ty: Type, + /// `pub`, `pub(crate)`, etc. + vis: Visibility, + /// Optional attributes to forward to the builder's field. forward: Option, } @@ -383,6 +386,7 @@ impl FieldImplementer { forward, from, try_from, + vis, .. } = field_impl.as_ref(); @@ -415,7 +419,7 @@ impl FieldImplementer { Ok(quote_spanned! { ident.span() => #[serde(default)] #forward - #ident #ty + #vis #ident #ty }) } @@ -628,6 +632,11 @@ struct RootImplementer { /// This can be serde attributes e.g. `#[confik(forward(serde(default)))]` but also others like /// `#[confik(forward(derive(Hash)))]` forward: Option, + + /// A name to use for the builder. + /// + /// Setting this also puts the builder in the local module, so that the name is accessible. + name: Option, } impl RootImplementer { @@ -655,7 +664,11 @@ impl RootImplementer { /// /// Use [`Self::is_dataless`] first to determine whether a builder will exist. fn builder_name(&self) -> Ident { - format_ident!("{}ConfigBuilder", self.ident) + if let Some(name) = self.name.as_ref() { + name.clone() + } else { + format_ident!("{}ConfigBuilder", self.ident) + } } /// Defines the builder for the target. @@ -920,18 +933,35 @@ fn derive_macro_builder_inner(target_struct: &DeriveInput) -> syn::Result::Builder; + +fn main() { + let _ = Builder { + param: Default::default(), + }; +} diff --git a/confik-macros/tests/trybuild/28-field-vis.rs b/confik-macros/tests/trybuild/28-field-vis.rs new file mode 100644 index 0000000..f185a2b --- /dev/null +++ b/confik-macros/tests/trybuild/28-field-vis.rs @@ -0,0 +1,19 @@ +//! Check that we can reference builder fields in a different module, when they're public + +pub mod config { + use confik::Configuration; + + #[derive(Configuration, Debug, PartialEq)] + pub struct Config { + #[confik(default)] + pub param: String, + } + + pub type Builder = ::Builder; +} + +fn main() { + let _ = config::Builder { + param: Default::default(), + }; +} diff --git a/confik-macros/tests/trybuild/29-named-field-vis.rs b/confik-macros/tests/trybuild/29-named-field-vis.rs new file mode 100644 index 0000000..f0e6ad8 --- /dev/null +++ b/confik-macros/tests/trybuild/29-named-field-vis.rs @@ -0,0 +1,18 @@ +//! Check that we can reference builder fields in a different module, when they're public, using the builder's name + +pub mod config { + use confik::Configuration; + + #[derive(Configuration, Debug, PartialEq)] + #[confik(name = Builder)] + pub struct Config { + #[confik(default)] + pub param: String, + } +} + +fn main() { + let _ = config::Builder { + param: Default::default(), + }; +} diff --git a/confik/CHANGELOG.md b/confik/CHANGELOG.md index db00f07..28825df 100644 --- a/confik/CHANGELOG.md +++ b/confik/CHANGELOG.md @@ -18,6 +18,13 @@ #[confik(forward(derive(Hash)))] struct Config(usize); ``` +- Add a new `confik(name = ...)` attribute, that provides a custom name for the `Configuration::Builder` `struct` or `enum`. + - This will also place the builder in the local module, so that its name is in a known location + ```rust + #[derive(Configuration)] + #[confik(name = Builder)] + struct Config {} + ``` ## 0.13.0 diff --git a/confik/src/lib.md b/confik/src/lib.md index b2c60d3..f2452ef 100644 --- a/confik/src/lib.md +++ b/confik/src/lib.md @@ -256,6 +256,38 @@ struct Config { } ``` +### Named builders + +If you want to directly access the builders, you can provide them with a name. This will also place the builder in the local module, to ensure there's a known path with which to reference them. + +```rust +#[derive(confik::Configuration)] +#[confik(name = Builder)] +struct Config { + data: usize, +} + +let _ = Builder { data: Default::default() }; +``` + +### Field and Builder visibility + +Field and builder visibility are directly inherited from the underlying type. E.g. + +```rust +mod config { + #[derive(confik::Configuration)] + pub struct Config { + pub data: usize, + } +} + +// Required as you can't use this syntax for struct initialisation. +type Builder = ::Builder; + +let _ = Builder { data: Default::default() }; +``` + ## Macro Limitations ### Custom `Deserialize` Implementations