Another builder macro-based generator with its own idioms.

"[Maçon](https://fr.wiktionary.org/wiki/ma%C3%A7on#Nom_commun_2)" is French translation for "[builder](https://www.wordreference.com/enfr/builder)"

### Usage

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyType {
  integer: i32,
  string: String,
  optional: Option<String>,
}

let _mytype: MyType = MyType::builder()
    .integer(42)
    .string("foobar")
    .build();
```

* adds a builder struct (`<TargetStruct>Builder`)
* build struct implements [`Default`][Default]
* adds a `builder()` function to target struct to initialize a new builder
* each target struct field can be set with function of same name and parameter of same type
* use `build()` function to create new target struct instance
* any unset field will make `build()` call not compile (default)
* setter argument is generic over [`Into`][Into]
* [`Option`][Option] fields are not mandatory. And setters use wrapped type.

### Settings

Settings are set using `#[builder()]` attribute.

#### struct

* **`mode=<value>`** <br/>
Change builder and associated `build()` function behavior. Supported values: [`Typestate`](#typestate-pattern-default) (_default_), [`Panic`](#panic-on-build) or [`Result`](#result-on-build).

* **`Option=!`** <br/>
Disable automatic [`Option`][Option] detection for whole struct. See ["`Option` fields"](#option-fields).

* **`Default=!`** <br/>
Disable automatic [`Default`][Default] derive detection for struct. See ["`Default` struct"](#default-struct).

* **`Default`** <br/>
Enforce [`Default`][Default] support for struct. See ["`Default` struct"](#default-struct).

#### field

* **`Option=!`** <br/>
Disable automatic [`Option`][Option] detection for given field. Generated setter will rely on declared field type. See ["`Option` fields"](#option-fields).

* **`Option=WrappedType`** <br/>
Enforce [`Option`][Option] support for given field. Generated setter will rely on `WrappedType`. See ["`Option` fields"](#option-fields).

* **`Default=!`** <br/>
Disable automatic [`Default`][Default] detection for given field. See ["`Default` fields"](#default-fields).

* **`Default`** <br/>
Enforce [`Default`][Default] support for given field. See ["`Default` fields"](#default-fields).

#### Configuration

Some additional configuration can be passed by adding a `macon-config.yaml` at crate root (also supports `.yml` and `.json` extensions).

Content example:

```yaml
version: "1" # Ignored

default_types:
  defaults: true
  includes:
  - my_crate::a_module::Foobar
  excludes:
  - usize

option_types:
  defaults: true
  includes:
  - my_crate::a_module::MyOption    # Must have a generic parameter
  - path: Flag                      # An alias for Option<bool>
    wrapped: bool
  excludes:
  - core::option::Option
```

Syntax description (all keys are optionals):

* **`version`** <br/>
Define configuration syntax version. Currently ignored.

* **`default_types`** <br/>
Configure automatic `Default` types.

* **`default_types.defaults`** <br/>
Include (or not) default values for `default_types`. Supported values: `true` (_default_) or `false`.

* **`default_types.excludes`** <br/>
List of pathes (e.g. `std::string::String`) to exclude (even if included). Default to empty.

* **`default_types.includes`** <br/>
List of pathes (e.g. `my_crate::a_module::Foobar`) to include. Default to empty.

* **`option_types`** <br/>
Configure automatic `Default` types.

* **`option_types.defaults`** <br/>
Include (or not) default values for `default_types`. Supported values: `true` (_default_) or `false`.

* **`option_types.excludes`** <br/>
List of pathes (e.g. `std::string::String`) to exclude (even if included). Default to empty.

* **`option_types.includes`** <br/>
List of pathes (e.g. `my_crate::a_module::MyOption`) as `String` or structured type. Default to empty.

* **`option_types.includes.path`** <br/>
Path that should be considered as an `Option`. Mandatory.

* **`option_types.includes.wrapped`** <br/>
Path of wrapped type. Optional, use first type argument if missing.

### Features

For any feature, you can find blueprints in [`./tests` directory)[tests] showing code generated by macro.

#### Typestate pattern (default)

Blueprints:
* [`blueprint_typestate_named.rs`][blueprint_typestate_named.rs]
* [`blueprint_typestate_tuple.rs`][blueprint_typestate_tuple.rs]
* [`blueprint_typestate_option.rs`][blueprint_typestate_option.rs]
* [`blueprint_typestate_default_field.rs`][blueprint_typestate_default_field.rs]
* [`blueprint_typestate_default_struct.rs`][blueprint_typestate_default_struct.rs]

By default, builder rely on typestate pattern. It means state is encoded in type (using generics). Applicable functions are implemented
(callable) only when state (type) matches:

* Build function `build()` when all properties has been set
* Each property setter function as long as property haven't been set

Optionally, you can set it explictly:

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
#[builder(mode=Typestate)]
struct MyType {
  integer: i32,
  string: String,
}
```

#### Panic on `build()`

Blueprints:
* [`blueprint_panic_named.rs`][blueprint_panic_named.rs]
* [`blueprint_panic_tuple.rs`][blueprint_panic_tuple.rs]
* [`blueprint_panic_option.rs`][blueprint_panic_option.rs]
* [`blueprint_panic_default_field.rs`][blueprint_panic_default_field.rs]
* [`blueprint_panic_default_struct.rs`][blueprint_panic_default_struct.rs]

By default, builder rely on typestate pattern to avoid misconfiguration by adding compilation constraint. You can switch to a builder
that just panic when misconfigured:

```rust
#[macro_use] extern crate macon;

use std::path::PathBuf;

#[derive(Builder)]
#[builder(mode=Panic)]
struct MyType {
  integer: i32,
  path: PathBuf,
}

let _mytype: MyType = MyType::builder()
    .integer(42)
    .build();
```

#### Result on `build()`

Blueprints:
* [`blueprint_result_named.rs`][blueprint_result_named.rs]
* [`blueprint_result_tuple.rs`][blueprint_result_tuple.rs]
* [`blueprint_result_option.rs`][blueprint_result_option.rs]
* [`blueprint_result_default_field.rs`][blueprint_result_default_field.rs]
* [`blueprint_result_default_struct.rs`][blueprint_result_default_struct.rs]

By default, builder rely on typestate pattern to avoid misconfiguration by adding compilation constraint. You can switch to a builder
that returns a [`Result`][Result]:

```rust
#[macro_use] extern crate macon;

use std::path::PathBuf;

#[derive(Builder)]
#[builder(mode=Result)]
struct MyType {
  integer: i32,
  string: String,
}

let myTypeResult: Result<MyType,String> = MyType::builder()
    .integer(42)
    .build();

assert_eq!(
  Err(String::from("Field path is missing")),
  myTypeResult.map(|_| ())
);
```

#### Tuple

Blueprints:
* [`blueprint_typestate_tuple.rs`][blueprint_typestate_tuple.rs]
* [`blueprint_panic_tuple.rs`][blueprint_panic_tuple.rs]
* [`blueprint_result_tuple.rs`][blueprint_result_tuple.rs]

Tuples are struct with unamed fields. Then `set<ordinal>()` is used as setter:

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyTuple(
  i32,
  Option<String>,
  String,
);

let _mytuple: MyTuple = MyTuple::builder()
    .set0(42)
    .set2(String::from("foobar"))
    .build();
```

Only for [`Typestate` mode](#typestate-pattern-default), you can use `set()`, [`none()`](#option-fields), [`keep()`](#default-struct) and [`default()`](#default-fields) calls to assign values in order:

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyTuple(
  i32,
  Option<String>,
  String,
);
let _mytuple: MyTuple = MyTuple::builder()
    .set(42)
    .none()
    .set(String::from("foobar"))
    .build();
```

#### `Into` argument

Blueprints:
* [`blueprint_typestate_named.rs`][blueprint_typestate_named.rs]
* [`blueprint_panic_named.rs`][blueprint_panic_named.rs]
* [`blueprint_result_named.rs`][blueprint_result_named.rs]

Setter function argument is generic over [`Into`][Into] to ease conversion (especially for `&str`):

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyTuple(
  String,
);
let _mytuple: MyTuple = MyTuple::builder()
    .set("foobar")
    .build();
```

#### Implement `Into`

Blueprints:
* [`blueprint_typestate_named.rs`][blueprint_typestate_named.rs]
* [`blueprint_panic_named.rs`][blueprint_panic_named.rs]
* [`blueprint_result_named.rs`][blueprint_result_named.rs]

Builders implement [`Into`][Into] for target type (and reverse [`From`][From] also). Except for `Result` mode which uses [`TryInto`][TryInto] / [`TryFrom`][TryFrom].

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyStruct {
  value: String,
};
let _mytuple: MyStruct = MyStruct::builder()
    .value("foobar")
    .into();
```

#### `Option` fields

Blueprints:
* [`blueprint_typestate_option.rs`][blueprint_typestate_option.rs]
* [`blueprint_panic_option.rs`][blueprint_panic_option.rs]
* [`blueprint_result_option.rs`][blueprint_result_option.rs]

As their name suggests, [`Option`][Option] fields are facultative: you can build instance without setting them explicitly.

Setter argument are still generic over [`Into`][Into] but for wrapped type. No need to wrap into an [`Option`][Option]:

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
struct WithOptional {
  mandatory: String,
  optional: Option<String>,
}

let built = WithOptional::builder()
  .optional("optional value")
  .mandatory("some value")
  .build();

assert_eq!(Some(String::from("optional value")), built.optional);
```

You can set them explicitly to [`None`][None] with `<field>_none()` or `none()` for ordered setter:

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
pub struct WithOptional {
  mandatory: String,
  optional: Option<String>,
}

let built = WithOptional::builder()
  .optional_none()
  .mandatory("some value")
  .build();

assert_eq!(None, built.optional);
```

<div class="warning">

Note: In order to detect optional fields, field type **name** must match:

* `core::option::Option`
* `::core::option::Option`
* `std::option::Option`
* `::std::option::Option`
* `Option`

</div>

You can disable [`Option`][Option] support by using `#[builder(Option=!)]` at struct or field level:

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
#[builder(Option=!)]
struct DisableOptionStruct {
  optional: Option<String>,
}

let built = DisableOptionStruct::builder()
  .optional(Some(String::from("mandatory value")))
  .build();

assert_eq!(Some(String::from("mandatory value")), built.optional);
```

If you use an alias, use `#[builder(Option=<WrappedType>)]` at field level to enable [`Option`][Option] support:

```rust
#[macro_use] extern crate macon;

type OptString = Option<String>;
#[derive(Builder)]
struct AliasedOptionStruct {
  #[builder(Option=String)]
  optional: OptString,
}

let built = AliasedOptionStruct::builder()
  .optional("aliased value")
  .build();

assert_eq!(Some(String::from("aliased value")), built.optional);
```

#### `Default` struct

Blueprints:
* [`blueprint_typestate_default_struct.rs`][blueprint_typestate_default_struct.rs]
* [`blueprint_panic_default_struct.rs`][blueprint_panic_default_struct.rs]
* [`blueprint_result_default_struct.rs`][blueprint_result_default_struct.rs]

If struct derives [`Default`][Default], all fields are then optional and values are kept from default instance:

<div class="warning">

Note: In order to detect [`Default`][Default] derive, `Builder` derive attribute must be placed before other derive attributes.

</div>

```rust
#[macro_use] extern crate macon;

#[derive(Builder,)]
#[derive(PartialEq,Debug,)]
#[builder(Default,)]
struct DeriveDefaultStruct {
  integer: usize,
  string: String,
  optional: Option<String>,
}

impl Default for DeriveDefaultStruct {
    fn default() -> Self {
        DeriveDefaultStruct {
            integer: 42,
            string: String::from("plop!"),
            optional: Some(String::from("some")),
        }
    }
}

let built = DeriveDefaultStruct::builder()
  .build();

assert_eq!(
  DeriveDefaultStruct {
    integer: 42,
    string: String::from("plop!"),
    optional: Some(String::from("some")),
  },
  built,
);
```

In case [`Default`][Default] derive detection is undesired, you can disable it with `#[builder(Default=!)]`.

On the other hand, if have your own [`Default`][Default] implementation, you can add `#[builder(Default)]` to enable support.

```rust
#[macro_use] extern crate macon;

#[derive(Builder,)]
#[derive(PartialEq,Debug,)]
#[builder(Default,)]
struct CustomDefaultStruct {
  integer: usize,
  string: String,
  optional: Option<String>,
}

impl Default for CustomDefaultStruct {
    fn default() -> Self {
        CustomDefaultStruct {
            integer: 42,
            string: String::from("plop!"),
            optional: Some(String::from("some")),
        }
    }
}

let built = CustomDefaultStruct::builder()
  .build();

assert_eq!(
  CustomDefaultStruct {
    integer: 42,
    string: String::from("plop!"),
    optional: Some(String::from("some")),
  },
  built,
);
```

You can keep default value (from default built instance) explicitly with `<field>_keep()` or `keep()` for ordered setter:

```rust
let built = CustomDefaultStruct::builder()
  .integer_keep()
  .string("overriden")
  .optional_none()
  .build();

assert_eq!(
  CustomDefaultStruct {
    integer: 42,
    string: String::from("overriden"),
    optional: None,
  },
  built,
);
```

#### `Default` fields

Blueprints:
* [`blueprint_typestate_default_field.rs`][blueprint_typestate_default_field.rs]
* [`blueprint_panic_default_field.rs`][blueprint_panic_default_field.rs]
* [`blueprint_result_default_field.rs`][blueprint_result_default_field.rs]

If field implements [`Default`][Default], it is then optional and value is:

1. kept from default instance if [struct derives `Default`](#default-struct),
1. or, initialized with default value.

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
#[derive(Debug,PartialEq,)]
struct WithDefaultFields {
  integer: usize,
  string: String,
  optional: Option<String>,
}

let built = WithDefaultFields::builder()
  .build();

assert_eq!(
  WithDefaultFields {
    integer: 0,
    string: String::from(""),
    optional: None,
  },
  built,
);
```

You can set them explicitly to default with `<field>_default()` or `default()` for ordered setter (e.g. [override default instance value](#default-struct)):

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
#[derive(Debug,PartialEq,)]
struct WithDefaultFields {
  integer: usize,
  string: String,
  optional: Option<String>,
}

let built = WithDefaultFields::builder()
  .integer_default()
  .string_default()
  .optional_default()
  .build();

assert_eq!(
  WithDefaultFields {
    integer: 0,
    string: String::from(""),
    optional: None,
  },
  built,
);
```

<div class="warning">

In order to detect default fields, field type **name** must match (leading `::` and module path are optionals):

* `bool`
* `char`
* `f32`
* `f64`
* `i8`
* `i16`
* `i32`
* `i64`
* `i128`
* `isize`
* `str`
* `u8`
* `u16`
* `u32`
* `u64`
* `u128`
* `usize`
* `std::string::String`
* `core::option::Option`
* `std::option::Option`
* `std::vec::Vec`
* `alloc::vec::Vec`
* `std::collections::HashMap`
* `std::collections::hash_map::HashMap`
* `std::collections::HashSet`
* `std::collections::hash_set::HashSet`

</div>

If you use an alias or unsupported type, use `#[builder(Default)]` at field level to enable [`Default`][Default] support:

```rust
#[macro_use] extern crate macon;

#[derive(Builder)]
#[derive(Debug,PartialEq,)]
struct ExplicitDefaultOnField {
  #[builder(Default)]
  boxed: Box<usize>,
}

let built = ExplicitDefaultOnField::builder()
    .build();

assert_eq!(
  ExplicitDefaultOnField {
    boxed: Box::from(0),
  },
  built,
);
```

You can disable [`Default`][Default] support by using `#[builder(Default=!)]` at field level:

```rust
// Don't compile
#[macro_use] extern crate macon;

#[derive(Builder)]
struct DisableDefaultOnField {
  #[builder(Default=!)]
  integer: usize,
}

DisableDefaultOnField::builder()
  .integer_default()
  .build();
```


[Default]: https://doc.rust-lang.org/core/default/trait.Default.html
[From]: https://doc.rust-lang.org/std/convert/trait.From.html
[Into]: https://doc.rust-lang.org/core/convert/trait.Into.html
[None]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.None
[Option]: https://doc.rust-lang.org/core/option/enum.Option.html
[Result]: https://doc.rust-lang.org/std/result/enum.Result.html
[TryFrom]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html
[TryInto]: https://doc.rust-lang.org/std/convert/trait.TryInto.html

[tests]: https://github.com/loganmzz/macon-rs/tree/0.3.0/tests
[blueprint_panic_default_field.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_panic_default_field.rs
[blueprint_panic_default_struct.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_panic_default_struct.rs
[blueprint_panic_named.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_panic_named.rs
[blueprint_panic_option.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_panic_option.rs
[blueprint_panic_tuple.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_panic_tuple.rs
[blueprint_result_default_field.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_result_default_field.rs
[blueprint_result_default_struct.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_result_default_struct.rs
[blueprint_result_named.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_result_named.rs
[blueprint_result_option.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_result_option.rs
[blueprint_result_tuple.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_result_tuple.rs
[blueprint_typestate_default_field.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_typestate_default_field.rs
[blueprint_typestate_default_struct.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_typestate_default_struct.rs
[blueprint_typestate_named.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_typestate_named.rs
[blueprint_typestate_option.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_typestate_option.rs
[blueprint_typestate_tuple.rs]: https://github.com/loganmzz/macon-rs/blob/0.3.0/tests/blueprint_typestate_tuple.rs
