optional_default/
lib.rs

1//!# optional-default
2//!A Helper macro to allow specifying default values for some fields of a rust struct while requiring some to be initialized manually.
3//!
4//!## Usage
5//!
6//!Add `optional-default` to your crate's dependencies: `cargo add optional-default`
7//!
8//!1. Annotate your struct with the `OptionalDefault` derive macro.
9//!2. Annotate any optional fields with `#[optional]`.
10//!3. If the field should have a default value other than `Default::default()`, or its type does not implement the `Default` trait, you can specify your own default value within the `#[optional(default = <value>)]`.
11//!4. The macro will generate a second macro with the same name as your struct. Use this macro to initialize the struct with your specified default values
12//!
13//!### Example
14//!```rust
15//!use optional_default::OptionalDefault;
16//!
17//!#[derive(Debug, OptionalDefault)]
18//!struct Example {
19//!    foo: i32, // Required field
20//!    #[optional]
21//!    bar: i32 // Optional, default = i32::default() = 0
22//!    #[optional(default = 10)]
23//!    baz: i32, // Optional, default = 10
24//!    
25//!}
26//!
27//!fn example() {
28//!    // Use the macro as if it was a struct declaration
29//!    let example1 = Example! {
30//!        foo: 1
31//!        // The other fields are set to their default values
32//!    };
33//!
34//!    println!("{:?}", example1); // Example { foo:1, bar: 0, baz: 10 }
35//!
36//!    let example2 = Example! {
37//!        foo: 1,
38//!        bar: 5
39//!    };
40//!
41//!    println!("{:?}", example2); // Example { foo:1, bar: 5, baz: 10 }
42//!
43//!    let example3 = Example! {
44//!        foo: 20,
45//!        baz: 0 // You can override the default values
46//!    };
47//!
48//!    println!("{:?}", example1); // Example { foo:1, bar: 0, baz: 20 }
49//!
50//!    let does_not_work = Example! {
51//!        baz: 0  
52//!    }; // Error: missing required field foo
53//!
54//!}
55//!```
56//!
57//!## Limitations
58//!Currently, the macro can only be placed on structs. While it would be possible to implement this approach for enums as well, the initialisation syntax would be inconsistent with regular enum initialisations as `Enum::Variant` would not be a valid macro name.
59//!
60//!
61mod check_helper;
62mod derive;
63
64#[proc_macro_derive(OptionalDefault, attributes(optional))]
65pub fn derive_optional_default(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
66    let input = syn::parse_macro_input!(input as syn::DeriveInput);
67    derive::optional_default(input).into()
68}
69
70#[proc_macro]
71pub fn check_required(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
72    let input = syn::parse_macro_input!(input as check_helper::CheckInput);
73    check_helper::check_required(input).into()
74}