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