fancy_constructor

Derive a highly configurable constructor for your struct


Keywords
configurable, constructor, derive, macro, new
License
Apache-2.0

Documentation

Derive a highly configurable constructor for your struct

MASTER CI status crates.io badge dependencies badge Coverage Status

Examples

Basic
use fancy_constructor::new;
#[derive(new, PartialEq, Eq, Debug)]
struct MyStruct {
  foo: String,
  bar: u8,
}

let a = MyStruct::new("#[derive(new)]".into(), 55);
let b = MyStruct { foo: "#[derive(new)]".into(), bar: 55 };
assert_eq!(a, b);

Outputs:

impl MyStruct {
  pub fn new(foo: String, bar: u8) -> Self {
    Self { foo, bar }
  }
}
Options showcase
#[derive(new, PartialEq, Eq, Debug)]
#[new(vis(pub(crate)), name(construct), comment("Foo"), bounds(T: Clone))]
struct MyStruct<T> {
  #[new(into)]
  a: T,

  #[new(val("Bar".into()))]
  b: String,

  #[new(clone)]
  c: Arc<Whatever>,

  #[new(default)]
  d: Vec<u8>,
}

let we = Arc::new(Whatever::default());
let a = MyStruct::<String>::construct("A", &we);
let b = MyStruct {a: "A".into(), b: "Bar".into(), c: we, d: vec![]};
assert_eq!(a, b);

Outputs:

impl<T> MyStruct<T> {
  /// Foo
  pub(crate) fn construct(a: impl Into<T>, c: &Arc<Whatever>) -> Self where T: Clone {
    Self {
      a: a.into(),
      b: "Bar".into(),
      c: c.clone(),
      d: Default::default(),
    }
  }
}
Private const fn
#[derive(new, PartialEq, Eq, Debug)]
#[new(const_fn, vis())]
struct Foo(u8);

const FOO: Foo = Foo::new(128);
assert_eq!(FOO, Foo(128));

Outputs:

impl Foo {
  const fn new(f1: u8) -> Self {
    Self(f1)
  }
}
Computed values
#[derive(new)]
struct Foo {
  is_bar: bool,
  #[new(val(if is_bar { 100 } else { 5 }))]
  barness_level: u8,
}

assert_eq!(Foo::new(true).barness_level, 100);
assert_eq!(Foo::new(false).barness_level, 5);
Custom constructor args
#[derive(new)]
#[new(args(input_string: &str))]
struct Foo {
  #[new(val(input_string.to_lowercase()))]
  pub lowercase: String,

  #[new(val(input_string.to_uppercase()))]
  pub uppercase: String,
}

let foo = Foo::new("Foo");
assert_eq!(foo.lowercase.as_str(), "foo");
assert_eq!(foo.uppercase.as_str(), "FOO");
Renaming constructor args
#[derive(new)]
struct MyNewtype(#[new(name(my_value))] u8);

Outputs:

impl MyNewtype {
  pub fn new(my_value: u8) -> Self {
    Self(my_value)
  }
}
Enums
#[derive(new, Eq, PartialEq, Debug)]
enum MyEnum {
  #[new]
  Foo { #[new(into)] bar: u8 },
  Qux,
}

assert_eq!(MyEnum::new(5), MyEnum::Foo { bar: 5 });

Outputs:

impl MyEnum {
  pub fn new(bar: Into<u8>) -> Self {
    Self::Foo { bar: bar.into() }
  }
}
Invalid inputs
#[derive(fancy_constructor::new)]
enum Foo {
  Bar, // no variants marked with `#[new]`
}
#[derive(fancy_constructor::new)]
enum Foo {
  #[new] Bar, // multiple variants marked with `#[new]`
  #[new] Qux,
}
#[derive(fancy_constructor::new)]
union Foo { // Unions not supported
  bar: u8,
  qux: u8,
}