default_struct_builder/
lib.rs

1//! Generates builder methods of every field of a struct. It is meant to be used on structs that
2//! implement `Default`. There is no separate builder struct generated and no need to call a
3//! `build()` method at the end or `.unwrap()`.
4//!
5//! This crate is used by the crate `leptos-use` for the option structs that
6//! can be passed to the various functions.
7//!
8//! ## Installation
9//!
10//! In your project folder run
11//!
12//! ```sh
13//! cargo add default-struct-builder
14//! ```
15//!
16//! ## Usage
17//!
18//! It is very easy to use:
19//!
20//! ```
21//! use default_struct_builder::DefaultBuilder;
22//!
23//! #[derive(DefaultBuilder, Default)]
24//! pub struct SomeOptions {
25//!     throttle: f64,
26//!
27//!     #[builder(into)]
28//!     offset: Option<f64>,
29//!
30//!     #[builder(skip)]
31//!     not_included: u32,
32//! }
33//! ```
34//!
35//! you can then use the struct like this:
36//!
37//! ```
38//! # use default_struct_builder::DefaultBuilder;
39//! #
40//! # #[derive(DefaultBuilder, Default)]
41//! # pub struct SomeOptions {
42//! #     throttle: f64,
43//! #
44//! #     #[builder(into)]
45//! #     offset: Option<f64>,
46//! #
47//! #     #[builder(skip)]
48//! #     not_included: u32,
49//! # }
50//! #
51//! # fn main() {
52//! let options = SomeOptions::default().offset(4.0);
53//!
54//! assert_eq!(options.offset, Some(4.0));
55//! assert_eq!(options.throttle, 0.0);
56//! assert_eq!(options.not_included, 0);
57//! # }
58//! ```
59//!
60//! ### Generics
61//!
62//! The macro is ready to be used on generic structs.
63//!
64//! ```
65//! use default_struct_builder::DefaultBuilder;
66//!
67//! #[derive(DefaultBuilder, Default)]
68//! pub struct SomeOptions<T>
69//! where
70//!     T: Default,
71//! {
72//!     some_field: T,
73//! }
74//! ```
75//!
76//! ### Doc comments
77//!
78//! All doc comments on fields are directly passed on to their generated setter methods.
79//!
80//! ## How it works
81//!
82//! The derive macro generates the following code:
83//!
84//! ```
85//! # #[derive(Default)]
86//! # pub struct SomeOptions {
87//! #     throttle: f64,
88//! #     offset: Option<f64>,
89//! #     not_included: u32,
90//! # }
91//! #
92//! impl SomeOptions {
93//!     // setter methods are given that consume `self` and return a new `Self` with the field value changed
94//!     pub fn throttle(self, value: f64) -> Self {
95//!         Self {
96//!             throttle: value,
97//!             ..self
98//!         }
99//!     }
100//!
101//!     // because `into` was specified this method is generic and calls `.into()` when setting the value
102//!     pub fn offset<T>(self, value: T) -> Self
103//!     where
104//!         T: Into<Option<f64>>,
105//!     {
106//!         Self {
107//!             offset: value.into(),
108//!             ..self
109//!         }
110//!     }
111//!
112//!     // no method for field `not_included` because `skip` was specified
113//! }
114//! ```
115//!
116//! ### Generics
117//!
118//! In the case of a generic field the generated method is a bit more complex because by calling
119//! the method the type of the type parameter can be different than before.
120//!
121//! Let's look at the following example.
122//!
123//! ```
124//! use default_struct_builder::DefaultBuilder;
125//!
126//! #[derive(DefaultBuilder, Default)]
127//! pub struct SomeOptions<T>
128//! where
129//!     T: Default,
130//! {
131//!     some_field: T,
132//!     other_field: i16,
133//! }
134//!
135//! impl SomeOptions<f32> {
136//!     pub fn new() -> Self {
137//!         Self {
138//!             some_field: 42.0,
139//!             other_field: 0,
140//!         }   
141//!     }
142//! }
143//! #
144//! # fn main() {
145//! #    let options = SomeOptions::new().some_field("string");
146//! # }
147//! ```
148//!
149//! This generates the setter method below.
150//!
151//! ```
152//! # pub struct SomeOptions<T>
153//! # where
154//! #     T: Default,
155//! # {
156//! #     some_field: T,
157//! #     other_field: i16,
158//! # }
159//! #
160//! # impl SomeOptions<f32> {
161//! #     pub fn new() -> Self {
162//! #         Self {
163//! #             some_field: 42.0,
164//! #             other_field: 0,
165//! #         }   
166//! #     }
167//! # }
168//! #
169//! impl<T> SomeOptions<T>
170//! where
171//!     T: Default,
172//! {
173//!     pub fn some_field<NewT>(self, value: NewT) -> SomeOptions<NewT>
174//!     where
175//!         NewT: Default,
176//!     {
177//!         SomeOptions::<NewT> {
178//!             some_field: value,
179//!             other_field: self.other_field,
180//!         }
181//!     }
182//! }
183//!
184//! fn main() {
185//!    let options = SomeOptions::new()  // at first    SomeOptions<f32>
186//!         .some_field("string");       // changed to  SomeOptions<&str>
187//! }
188//! ```
189//!
190//! In cases where you don't want a generic field to be able to change the generic type you
191//! can annotate it with `keep_type`.
192//!
193//! ```
194//! # use default_struct_builder::DefaultBuilder;
195//! #
196//! #[derive(DefaultBuilder)]
197//! struct SomeOptions<T> {
198//!     #[builder(keep_type)]
199//!     the_field: T,
200//! }
201//! ```
202//!
203//! this will generate a standard builder method as if `T` wasn't generic.
204//!
205//! ### `Box`, `Rc` and `Arc`
206//!
207//! The macro detects if a field is a `Box` (or `Rc` or `Arc`) and generates a builder method that
208//! accepts the inner type (without `Box` or `Rc` or `Arc`) and adds the outer type in the body.
209//!
210//! In case it's a `Box<dyn Trait>` the builder method will have an argument of type
211//! `impl Trait`. The same goes for `Rc` and `Arc`.
212//!
213//! If you want to prevent this auto un-wrapping you can use the `#[builder(keep_outer)]` attribute.
214//!
215//! ```
216//! # use std::rc::Rc;
217//! # use default_struct_builder::DefaultBuilder;
218//! #
219//! trait Test {}
220//!
221//! #[derive(DefaultBuilder)]
222//! struct SomeOptions {
223//!     the_field: Box<dyn Test>,
224//!     other_field: Rc<String>,
225//!
226//!     #[builder(keep_outer)]
227//!     keep: Box<String>,
228//! }
229//! ```
230//!
231//! This will generate the following code:
232//!
233//! ```
234//! # use std::rc::Rc;
235//! # use default_struct_builder::DefaultBuilder;
236//! #
237//! # trait Test {}
238//! #
239//! # struct SomeOptions {
240//! #     the_field: Box<dyn Test>,
241//! #     other_field: Rc<String>,
242//! #     keep: Box<String>,
243//! # }
244//! #
245//! impl SomeOptions {
246//!     pub fn the_field(self, value: impl Test + 'static) -> Self {
247//!         Self {
248//!             the_field: Box::new(value),
249//!             ..self
250//!         }   
251//!     }
252//!
253//!     pub fn other_field(self, value: String) -> Self {
254//!         Self {
255//!             other_field: Rc::new(value),
256//!             ..self
257//!         }
258//!     }
259//!
260//!     pub fn keep(self, value: Box<String>) -> Self {
261//!         Self {
262//!             keep: value,
263//!             ..self
264//!         }   
265//!     }
266//! }
267//! ```
268//!
269//!
270//! ## Related Work
271//!
272//! For more general purposes please check out the much more powerful
273//! [`derive_builder` crate](https://github.com/colin-kiegel/rust-derive-builder).
274
275mod builder;
276
277use builder::DefaultBuilderDeriveInput;
278use darling::FromDeriveInput;
279use proc_macro::TokenStream;
280use quote::ToTokens;
281use syn::parse_macro_input;
282
283#[proc_macro_derive(DefaultBuilder, attributes(builder))]
284pub fn derive_builder(input: TokenStream) -> TokenStream {
285    let input = parse_macro_input!(input as syn::DeriveInput);
286    let data = DefaultBuilderDeriveInput::from_derive_input(&input);
287    let stream = match data {
288        Ok(data) => data.into_token_stream(),
289        Err(err) => err.write_errors(),
290    };
291    stream.into()
292}