I have a newtype wrapper pattern with my struct:
pub struct Config(Arc<ConfigInner>);
struct ConfigInner {
setting_a: bool,
setting_b: String,
}
I'd like to use bon to make a builder for Config
, but I'm not seeing anything in the documentation that describes how to deal with a newtype-pattern struct like I'm doing here.
I've used bon for many other projects in the past, but this is my first time dealing with this.
Is there a way to configure bon to define a builder on Config
which successfully wraps the inner value?
After some help from the creator (thank you!!!) I arrived at this:
pub mod config {
use bon::Builder;
use std::sync::Arc;
#[derive(Clone)]
pub struct Config(Arc<ConfigInner>);
impl Config {
pub fn builder() -> ConfigBuilder {
ConfigInner::builder()
}
}
#[derive(Builder)]
#[builder(
builder_type = ConfigBuilder,
finish_fn(name = build_internal, vis="")
)]
struct ConfigInner {
#[builder(into)]
default_global_level: Option<String>,
default_directives: Vec<String>,
}
impl<S: config_builder::IsComplete> ConfigBuilder<S> {
pub fn build(self) -> Config {
Config(Arc::new(self.build_internal()))
}
}
}
let c = Config::builder()
.default_global_level("INFO".into())
.default_directives(vec!["a=ERROR".to_string()])
.build();
Unfortunately I'm getting visibility errors now:
[E0624] Error: method `default_global_level` is private
╭─[command_10:1:1]
│
18 │ #[derive(Builder)]
│ ───┬───
│ ╰───── private method defined here
│
37 │ .default_global_level("INFO".into())
│ ──────────┬─────────
│ ╰─────────── private method
────╯
Arrived at the solution with the help of the maintainer, thanks again!
use bon;
pub mod config {
use bon::Builder;
use std::sync::Arc;
#[derive(Clone)]
pub struct Config(Arc<ConfigInner>);
impl Config {
pub fn builder() -> ConfigBuilder {
ConfigInner::builder()
}
}
#[derive(Builder)]
#[builder(
builder_type(vis = "pub", name = ConfigBuilder),
finish_fn(name = build_internal, vis="")
)]
struct ConfigInner {
#[builder(into)]
default_global_level: Option<String>,
default_directives: Vec<String>,
}
impl<S: config_builder::IsComplete> ConfigBuilder<S> {
pub fn build(self) -> Config {
Config(Arc::new(self.build_internal()))
}
}
}
fn main() {
let c = config::Config::builder()
.default_global_level("INFO")
.default_directives(vec!["a=ERROR".to_string()])
.build();
}
2 Likes
Bon is impressively flexible, I'm a big fan.
I bet you'd even be able to get default_directives
to accept [&'str]
so you could write:
let c = config::Config::builder()
.default_global_level("INFO")
.default_directives(["a=ERROR"])
.build();