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}