bon_macros/
lib.rs

1#![doc = include_str!("../README.md")]
2#![allow(
3    clippy::redundant_pub_crate,
4    clippy::wildcard_imports,
5    clippy::map_unwrap_or,
6    clippy::items_after_statements,
7    clippy::missing_const_for_fn,
8    clippy::option_option,
9    clippy::option_if_let_else,
10    clippy::enum_glob_use,
11    clippy::too_many_lines,
12    clippy::if_not_else,
13
14    // We can't use the explicit captures syntax due to the MSRV
15    impl_trait_overcaptures,
16
17    // There are too many false-positives for syn::Ident
18    if_let_rescope,
19)]
20
21mod bon;
22mod builder;
23mod collections;
24mod error;
25mod normalization;
26mod parsing;
27mod privatize;
28mod util;
29
30#[cfg(test)]
31mod tests;
32
33/// Generates a builder for the function or method it's placed on.
34///
35/// ## Quick examples
36///
37/// You can turn a function with positional parameters into a function with
38/// named parameters just by placing the `#[builder]` attribute on top of it.
39///
40/// ```rust ignore
41/// use bon::builder;
42///
43/// #[builder]
44/// fn greet(name: &str, level: Option<u32>) -> String {
45///     let level = level.unwrap_or(0);
46///
47///     format!("Hello {name}! Your level is {level}")
48/// }
49///
50/// let greeting = greet()
51///     .name("Bon")
52///     .level(24) // <- setting `level` is optional, we could omit it
53///     .call();
54///
55/// assert_eq!(greeting, "Hello Bon! Your level is 24");
56/// ```
57///
58/// You can also use the `#[builder]` attribute with associated methods:
59///
60/// ```rust ignore
61/// use bon::bon;
62///
63/// struct User {
64///     id: u32,
65///     name: String,
66/// }
67///
68/// #[bon] // <- this attribute is required on impl blocks that contain `#[builder]`
69/// impl User {
70///     #[builder]
71///     fn new(id: u32, name: String) -> Self {
72///         Self { id, name }
73///     }
74///
75///     #[builder]
76///     fn greet(&self, target: &str, level: Option<&str>) -> String {
77///         let level = level.unwrap_or("INFO");
78///         let name = &self.name;
79///
80///         format!("[{level}] {name} says hello to {target}")
81///     }
82/// }
83///
84/// // The method named `new` generates `builder()/build()` methods
85/// let user = User::builder()
86///     .id(1)
87///     .name("Bon".to_owned())
88///     .build();
89///
90/// // All other methods generate `method_name()/call()` methods
91/// let greeting = user
92///     .greet()
93///     .target("the world")
94///     // `level` is optional, we can omit it here
95///     .call();
96///
97/// assert_eq!(user.id, 1);
98/// assert_eq!(user.name, "Bon");
99/// assert_eq!(greeting, "[INFO] Bon says hello to the world");
100/// ```
101///
102/// The builder never panics. Any mistakes such as missing required fields
103/// or setting the same field twice will be reported as compile-time errors.
104///
105/// See the full documentation for more details:
106/// - [Guide](https://bon-rs.com/guide/overview)
107/// - [Attributes reference](https://bon-rs.com/reference/builder)
108#[proc_macro_attribute]
109pub fn builder(
110    params: proc_macro::TokenStream,
111    item: proc_macro::TokenStream,
112) -> proc_macro::TokenStream {
113    builder::generate_from_attr(params.into(), item.into()).into()
114}
115
116/// Derives a builder for the struct it's placed on.
117///
118/// ## Quick example
119///
120/// Add a `#[derive(Builder)]` attribute to your struct to generate a `builder()` method for it.
121///
122/// ```rust ignore
123/// use bon::{bon, builder, Builder};
124///
125/// #[derive(Builder)]
126/// struct User {
127///     name: String,
128///     is_admin: bool,
129///     level: Option<u32>,
130/// }
131///
132/// let user = User::builder()
133///     .name("Bon".to_owned())
134///     // `level` is optional, we could omit it here
135///     .level(24)
136///     // call setters in any order
137///     .is_admin(true)
138///     .build();
139///
140/// assert_eq!(user.name, "Bon");
141/// assert_eq!(user.level, Some(24));
142/// assert!(user.is_admin);
143/// ```
144///
145/// The builder never panics. Any mistakes such as missing required fields
146/// or setting the same field twice will be reported as compile-time errors.
147///
148/// See the full documentation for more details:
149/// - [Guide](https://bon-rs.com/guide/overview)
150/// - [Attributes reference](https://bon-rs.com/reference/builder)
151#[proc_macro_derive(Builder, attributes(builder))]
152pub fn derive_builder(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
153    builder::generate_from_derive(item.into()).into()
154}
155
156/// Companion macro for [`builder`]. You should place it on top of the `impl` block
157/// where you want to define methods with the [`builder`] macro.
158///
159/// It provides the necessary context to the [`builder`] macros on top of the functions
160/// inside of the `impl` block. You'll get compile errors without that context.
161///
162/// # Quick example
163///
164/// ```rust ignore
165/// use bon::bon;
166///
167/// struct User {
168///     id: u32,
169///     name: String,
170/// }
171///
172/// #[bon] // <- this attribute is required on impl blocks that contain `#[builder]`
173/// impl User {
174///     #[builder]
175///     fn new(id: u32, name: String) -> Self {
176///         Self { id, name }
177///     }
178///
179///     #[builder]
180///     fn greet(&self, target: &str, level: Option<&str>) -> String {
181///         let level = level.unwrap_or("INFO");
182///         let name = &self.name;
183///
184///         format!("[{level}] {name} says hello to {target}")
185///     }
186/// }
187///
188/// // The method named `new` generates `builder()/build()` methods
189/// let user = User::builder()
190///     .id(1)
191///     .name("Bon".to_owned())
192///     .build();
193///
194/// // All other methods generate `method_name()/call()` methods
195/// let greeting = user
196///     .greet()
197///     .target("the world")
198///     // `level` is optional, we can omit it here
199///     .call();
200///
201/// assert_eq!(user.id, 1);
202/// assert_eq!(user.name, "Bon");
203/// assert_eq!(greeting, "[INFO] Bon says hello to the world");
204/// ```
205///
206/// The builder never panics. Any mistakes such as missing required fields
207/// or setting the same field twice will be reported as compile-time errors.
208///
209/// For details on this macro [see the overview](https://bon-rs.com/guide/overview).
210///
211/// [`builder`]: macro@builder
212#[proc_macro_attribute]
213pub fn bon(
214    params: proc_macro::TokenStream,
215    item: proc_macro::TokenStream,
216) -> proc_macro::TokenStream {
217    bon::generate(params.into(), item.into()).into()
218}
219
220/// Creates any map-like collection that implements [`FromIterator<(K, V)>`].
221///
222/// It automatically converts each key and value to the target type using [`Into`].
223/// This way you can write a map of `String`s without the need to call `.to_owned()`
224/// or `.to_string()` on every string literal:
225///
226/// ```rust
227/// # use bon_macros as bon;
228/// # use std::collections::HashMap;
229/// let map: HashMap<String, String> = bon::map! {
230///     "key1": "value1",
231///     format!("key{}", 2): "value2",
232///     "key3": format!("value{}", 3),
233/// };
234/// ```
235///
236/// There is no separate variant for [`BTreeMap`] and [`HashMap`]. Instead, you
237/// should annotate the return type of this macro with the desired type or make
238/// sure the compiler can infer the collection type from other context.
239///
240/// # Compile errors
241///
242/// The macro conservatively rejects duplicate keys in the map with a compile error.
243/// This check works for very simple expressions that involve only literal values.
244///
245/// ```rust compile_fail
246/// # use bon_macros as bon;
247/// # use std::collections::HashMap;
248/// let map: HashMap<String, String> = bon::map! {
249///     "key1": "value1",
250///     "key2": "value2"
251///     "key1": "value3", // compile error: `duplicate key in the map`
252/// };
253/// ```
254///
255/// [`FromIterator<(K, V)>`]: https://doc.rust-lang.org/stable/std/iter/trait.FromIterator.html
256/// [`Into`]: https://doc.rust-lang.org/stable/std/convert/trait.Into.html
257/// [`BTreeMap`]: https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html
258/// [`HashMap`]: https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html
259#[proc_macro]
260pub fn map(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
261    let entries = syn::parse_macro_input!(input with collections::map::parse_macro_input);
262
263    collections::map::generate(entries).into()
264}
265
266/// Creates any set-like collection that implements [`FromIterator<T>`].
267///
268/// It automatically converts each value to the target type using [`Into`].
269/// This way you can write a set of `String`s without the need to call `.to_owned()`
270/// or `.to_string()` on every string literal:
271///
272/// ```rust
273/// # use bon_macros as bon;
274/// # use std::collections::HashSet;
275/// let set: HashSet<String> = bon::set![
276///     "value1",
277///     format!("value{}", 2),
278///     "value3",
279/// ];
280/// ```
281///
282/// There is no separate variant for [`BTreeSet`] and [`HashSet`]. Instead, you
283/// should annotate the return type of this macro with the desired type or make
284/// sure the compiler can infer the collection type from other context.
285///
286/// # Compile errors
287///
288/// The macro conservatively rejects duplicate values in the set with a compile error.
289/// This check works for very simple expressions that involve only literal values.
290///
291/// ```rust compile_fail
292/// # use bon_macros as bon;
293/// # use std::collections::HashSet;
294/// let set: HashSet<String> = bon::set![
295///     "value1",
296///     "value2"
297///     "value1", // compile error: `duplicate value in the set`
298/// ];
299/// ```
300///
301/// [`FromIterator<T>`]: https://doc.rust-lang.org/stable/std/iter/trait.FromIterator.html
302/// [`Into`]: https://doc.rust-lang.org/stable/std/convert/trait.Into.html
303/// [`BTreeSet`]: https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html
304/// [`HashSet`]: https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html
305#[proc_macro]
306pub fn set(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
307    use syn::punctuated::Punctuated;
308
309    let entries = syn::parse_macro_input!(input with Punctuated::parse_terminated);
310
311    collections::set::generate(entries).into()
312}
313
314// Private implementation detail. Don't use it directly!
315// This attribute renames the function provided to it to `__orig_{fn_name}`
316#[doc(hidden)]
317#[proc_macro_attribute]
318pub fn __privatize(
319    _params: proc_macro::TokenStream,
320    input: proc_macro::TokenStream,
321) -> proc_macro::TokenStream {
322    privatize::privatize_fn(input.into()).into()
323}