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}