const_builder/
lib.rs

1//! Provides a [`ConstBuilder`] derive macro that generates a `*Builder` type
2//! that can be used to create a value with the builder pattern, even in a const
3//! context.
4//!
5//! The attributed type will gain an associated `builder` method, which can then
6//! be chained with function calls until all required fields are set, at which
7//! point you can call `build` to get the final value.
8//!
9//! Compile-time checks prevent setting the same field twice or calling `build`
10//! before all required fields are set.
11//!
12//! By default, the `*Builder` type and `*::builder` method have the same
13//! visibility as the type, and every field setter is `pub`, regardless of field
14//! visibility.
15//!
16//! The builder isn't clonable and its methods are called by-value, returning
17//! the updated builder value.
18//!
19//! The generated code is supported in `#![no_std]` crates.
20//!
21//! # Unsafety
22//!
23//! This derive macro generates `unsafe` code using
24//! [`MaybeUninit`](std::mem::MaybeUninit) to facilitate field-wise
25//! initialization of a struct, tracking initialized fields via const-generics.
26//! This broadly follows the guidance in the [nomicon section on unchecked
27//! uninitialized memory], and is, for now, required to get const-compatible
28//! builders for arbitrary types.
29//!
30//! # Struct Requirements
31//!
32//! All struct fields must be [`Sized`]. Fields using generic parameters may be
33//! [`?Sized`](Sized) for some parameters, as long as the actual instantiation
34//! of the builder only has [`Sized`] fields.
35//!
36//! When the struct is `#[repr(packed)]` and the last field may be
37//! [`?Sized`](Sized), the field needs to be attributed with
38//! `#[builder(unsized_tail)]` to replace the field drop code with an assert
39//! that the field cannot be dropped. Rust functionally currently requires this
40//! combination of packed and unsized tails to be
41//! [`ManuallyDrop`](std::mem::ManuallyDrop) or a wrapper around it.
42//!
43//! `enum` and `union` types are unsupported.
44//!
45//! # Default Values
46//!
47//! Fields can be attributed with `#[builder(default = None)]` or similar to
48//! be made optional by providing a default value.
49//!
50//! This default value will _not_ be dropped if it is overridden or the builder
51//! is dropped. Consequently, the value should be something that does not need
52//! to be dropped, such as a primitive, [`None`], [`String::new()`],
53//! [`Vec::new()`], [`Cow::Borrowed`](std::borrow::Cow), or similar.
54//!
55//! # Unchecked Builder
56//!
57//! There is also an `*UncheckedBuilder` without safety checks, which is
58//! private by default. This struct is used to simplify the implementation of
59//! the checked builder and it is exposed for users that want additional
60//! control.
61//!
62//! This builder works broadly in the same way as the checked builder, however:
63//!
64//! - initialized fields aren't tracked,
65//! - setting fields that were already set will forget the old value,
66//! - calling `build` is unsafe due to the lack of tracking, and
67//! - dropping it will forget all field values that were already set.
68//!
69//! Furthermore, its API isn't stable across modifications of the source struct.
70//! In particular, adding or removing a field to the struct is a breaking change
71//! to the API of the unchecked builder, so it should not be exposed in stable
72//! public interfaces.
73//!
74//! You can convert between the checked and unchecked builder with
75//! `*Builder::into_unchecked` and `*UncheckedBuilder::assert_init`.
76//!
77//! # Example
78//!
79//! ```
80//! use const_builder::ConstBuilder;
81//!
82//! #[derive(ConstBuilder)]
83//! # #[derive(Debug, PartialEq)]
84//! pub struct Person<'a> {
85//!     // fields are required by default
86//!     pub name: &'a str,
87//!     // optional fields have a default specified
88//!     // the value is required even when the type implements `Default`!
89//!     #[builder(default = 0)]
90//!     pub age: u32,
91//! }
92//!
93//! let steve = const {
94//!     Person::builder()
95//!         .name("steve smith")
96//!         .build()
97//! };
98//! # assert_eq!(
99//! #     steve,
100//! #     Person {
101//! #         name: "steve smith",
102//! #         age: 0,
103//! #     }
104//! # );
105//! ```
106//!
107//! # Generated Interface
108//!
109//! The example above would generate an interface similar to the following. The
110//! actual generated code is more complex because it includes bounds to ensure
111//! fields are only written once and that the struct is fully initialized when
112//! calling `build`.
113//!
114//! ```
115//! # // This isn't an example to run, just an example "shape".
116//! # _ = stringify!(
117//! /// A builder type for [`Person`].
118//! pub struct PersonBuilder<'a, const _NAME: bool = false, const _AGE: bool = false> { ... }
119//!
120//! impl<'a, ...> PersonBuilder<'a, ...> {
121//!     /// Creates a new builder.
122//!     pub const fn new() -> Self;
123//!
124//!     /// Returns the finished value.
125//!     ///
126//!     /// This function can only be called when all required fields have been set.
127//!     pub const fn build(self) -> Person<'a>;
128//!
129//!     // one setter function per field
130//!     pub const fn name(self, value: &'a str) -> PersonBuilder<'a, ...>;
131//!     pub const fn age(self, value: u32) -> PersonBuilder<'a, ...>;
132//!
133//!     /// Unwraps this builder into its unsafe counterpart.
134//!     ///
135//!     /// This isn't unsafe in itself, however using it carelessly may lead to
136//!     /// leaking objects and not dropping initialized values.
137//!     const fn into_unchecked(self) -> PersonUncheckedBuilder<'a>;
138//! }
139//!
140//! impl<'a> Person<'a> {
141//!     /// Creates a new builder for this type.
142//!     pub const fn builder() -> PersonBuilder<'a>;
143//! }
144//!
145//! /// An _unchecked_ builder type for [`Person`].
146//! ///
147//! /// This version being _unchecked_ means it has less safety guarantees:
148//! /// - No tracking is done whether fields are initialized, so [`Self::build`] is `unsafe`.
149//! /// - If dropped, already initialized fields will be leaked.
150//! /// - The same field can be set multiple times. If done, the old value will be leaked.
151//! struct PersonUncheckedBuilder<'a> { ... }
152//!
153//! impl<'a> PersonUncheckedBuilder<'a> {
154//!    /// Creates a new unchecked builder.
155//!    pub const fn new() -> Self;
156//!
157//!    /// Asserts that the fields specified by the const generics as well as all optional
158//!    /// fields are initialized and promotes this value into a checked builder.
159//!    ///
160//!    /// # Safety
161//!    ///
162//!    /// The fields whose const generic are `true` and all optional fields have to be
163//!    /// initialized.
164//!    ///
165//!    /// Optional fields are initialized by [`Self::new`] by default, however using
166//!    /// [`Self::as_uninit`] allows de-initializing them. This means that this function
167//!    /// isn't even necessarily safe to call if all const generics are `false`.
168//!    pub const unsafe fn assert_init<const _NAME: bool, const _AGE: bool>(self) -> PersonBuilder<'a, _NAME, _AGE>;
169//!
170//!    /// Returns the finished value.
171//!    ///
172//!    /// # Safety
173//!    ///
174//!    /// This function requires that all fields have been initialized.
175//!    pub const unsafe fn build(self) -> Person<'a>;
176//!
177//!    // one setter function per field
178//!    pub const fn name(mut self, value: &'a str) -> PersonUncheckedBuilder<'a>;
179//!    pub const fn age(mut self, value: u32) -> PersonUncheckedBuilder<'a>;
180//!
181//!    /// Gets a mutable reference to the partially initialized data.
182//!    pub const fn as_uninit(&mut self) -> &mut ::core::mem::MaybeUninit<Person<'a>>;
183//! }
184//! # );
185//! ```
186//!
187//! # Struct Attributes
188//!
189//! These attributes can be specified within `#[builder(...)]` on the struct
190//! level.
191//!
192//! | Attribute           | Meaning |
193//! |:------------------- |:------- |
194//! | `default`           | Generate a const-compatible `*::default()` function and [`Default`] derive. Requires every field to have a default value. |
195//! | `vis`               | Change the visibility of the builder type. May be an empty string for private. Default is the same as the struct. |
196//! | `rename`            | Renames the builder type. Defaults to `"<Type>Builder"`. |
197//! | `rename_fn`         | Renames the associated function that creates the builder. Defaults to `builder`. Set to `false` to disable. |
198//! | `unchecked(vis)`    | Change the visibility of the unchecked builder type. Default is private. |
199//! | `unchecked(rename)` | Renames the unchecked builder type. Defaults to `"<Type>UncheckedBuilder"`. |
200//!
201//! # Field Attributes
202//!
203//! These attributes can be specified within `#[builder(...)]` on the struct's
204//! fields.
205//!
206//! | Attribute              | Meaning |
207//! |:---------------------- |:------- |
208//! | `vis`                  | Change the visibility of the builder's field setter. May be an empty string for private. Default is `pub`. |
209//! | `default`              | Make the field optional by providing a default value. |
210//! | `rename`               | Renames the setters for this field. Defaults to the field name. |
211//! | `rename_generic`       | Renames the name of the associated const generic. Defaults to `_{field:upper}`. |
212//! | `leak_on_drop`         | Instead of dropping the field when dropping the builder, do nothing. |
213//! | `unsized_tail`         | In a packed struct, marks the last field as potentially being unsized, replacing the drop code with an assert. No effect if the struct isn't packed. |
214//! | `setter(transform)`    | Accepts closure syntax. The setter is changed to accept its inputs and set the corresponding value to its output. |
215//! | `setter(strip_option)` | On an [`Option<T>`] field, change the setter to accept `T` and wrap it in [`Some`] itself. Equivalent to `setter(transform = \|value: T\| Some(value))`. |
216//!
217//! # Attributes Example
218//!
219//! ```
220//! use const_builder::ConstBuilder;
221//!
222//! #[derive(ConstBuilder)]
223//! // change the builder from pub (same as Person) to crate-internal
224//! // also override the name of the builder to `CreatePerson`
225//! #[builder(vis = "pub(crate)", rename = "CreatePerson")]
226//! // change the unchecked builder from priv also to crate-internal
227//! #[builder(unchecked(vis = "pub(crate)"))]
228//! # #[derive(Debug, PartialEq)]
229//! pub struct Person<'a> {
230//!     // required field with public setter
231//!     name: &'a str,
232//!     // optional field with public setter
233//!     #[builder(default = 0)]
234//!     age: u32,
235//!     // optional field with private setter
236//!     #[builder(default = 1, vis = "" /* priv */)]
237//!     version: u32,
238//! }
239//!
240//! # assert_eq!(
241//! #     const {
242//! #         Person::builder()
243//! #             .name("smith")
244//! #             .build()
245//! #     },
246//! #     Person {
247//! #         name: "smith",
248//! #         age: 0,
249//! #         version: 1,
250//! #     }
251//! # );
252//! ```
253//!
254//! [nomicon section on unchecked uninitialized memory]: https://doc.rust-lang.org/nomicon/unchecked-uninit.html
255
256#![forbid(unsafe_code)]
257#![warn(clippy::doc_markdown)]
258
259use proc_macro::TokenStream;
260use syn::{DeriveInput, parse_macro_input};
261
262mod const_builder_impl;
263mod model;
264mod util;
265
266/// Generates the builder types for the attributed struct.
267///
268/// See the crate-level documentation for more details.
269#[proc_macro_derive(ConstBuilder, attributes(builder))]
270pub fn derive_const_builder(input: TokenStream) -> TokenStream {
271    let input = parse_macro_input!(input as DeriveInput);
272    const_builder_impl::entry_point(input)
273        .unwrap_or_else(|e| e.write_errors())
274        .into()
275}
276
277/// ```compile_fail
278/// #[derive(const_builder::ConstBuilder)]
279/// struct TupleStruct(u32, u64);
280/// ```
281///
282/// ```compile_fail
283/// #[derive(const_builder::ConstBuilder)]
284/// struct UnitStruct;
285/// ```
286///
287/// ```compile_fail
288/// #[derive(const_builder::ConstBuilder)]
289/// enum Enum { B { a: u32, b: u64 } }
290/// ```
291///
292/// ```compile_fail
293/// #[derive(const_builder::ConstBuilder)]
294/// union Union { a: u32, b: u64 }
295/// ```
296///
297/// ```compile_fail
298/// #[derive(const_builder::ConstBuilder)]
299/// #[builder(default)]
300/// struct InvalidDefault {
301///     a: u32,
302///     #[builder(default = 0)]
303///     b: u32,
304/// }
305/// ```
306///
307/// ```compile_fail
308/// #[derive(const_builder::ConstBuilder)]
309/// struct WrongUnsizedTailPosition {
310///     #[builder(unsized_tail)]
311///     a: u32,
312///     b: u32,
313/// }
314/// ```
315///
316/// ```compile_fail
317/// #[derive(const_builder::ConstBuilder)]
318/// struct UnsizedField {
319///     a: [u32],
320/// }
321/// ```
322///
323/// ```compile_fail
324/// // this test actually fails for two reasons:
325/// // - rust disallowing possible-Drop unsized tails in packed structs
326/// // - static assert when a packed struct's `unsized_tail` field `needs_drop`
327/// #[derive(const_builder::ConstBuilder)]
328/// #[repr(Rust, packed)]
329/// struct PackedUnsizedDropTail<T: ?Sized> {
330///     #[builder(unsized_tail)]
331///     a: T,
332/// }
333///
334/// // ensure a variant with a `needs_drop` tail is instantiated
335/// _ = PackedUnsizedDropTail::<String>::builder();
336/// ```
337///
338/// ```compile_fail
339/// #[derive(const_builder::ConstBuilder)]
340/// struct SetterCastNoClosure {
341///     #[builder(setter(transform))]
342///     value: Option<u32>,
343/// }
344/// ```
345///
346/// ```compile_fail
347/// #[derive(const_builder::ConstBuilder)]
348/// struct SetterCastNotAClosure1 {
349///     #[builder(setter(transform = r#""hello""#))]
350///     value: Option<u32>,
351/// }
352/// ```
353///
354/// ```compile_fail
355/// #[derive(const_builder::ConstBuilder)]
356/// struct SetterCastNotAClosure2 {
357///     #[builder(setter(transform = 42))]
358///     value: Option<u32>,
359/// }
360/// ```
361///
362/// ```compile_fail
363/// #[derive(const_builder::ConstBuilder)]
364/// struct SetterCastNotAClosure3 {
365///     #[builder(setter(transform = Some(42)))]
366///     value: Option<u32>,
367/// }
368/// ```
369///
370/// ```compile_fail
371/// #[derive(const_builder::ConstBuilder)]
372/// struct SetterCastNoType {
373///     #[builder(setter(transform = |i| Some(i)))]
374///     value: Option<u32>,
375/// }
376/// ```
377///
378/// ```compile_fail
379/// #[derive(const_builder::ConstBuilder)]
380/// struct SetterCastNoTypePartial1 {
381///     #[builder(setter(transform = |a: u32, b| a + b))]
382///     value: u32,
383/// }
384/// ```
385///
386/// ```compile_fail
387/// #[derive(const_builder::ConstBuilder)]
388/// struct SetterCastNoTypePartial2 {
389///     #[builder(setter(transform = |a, b: u32| a + b))]
390///     value: u32,
391/// }
392/// ```
393///
394/// ```compile_fail
395/// #[derive(const_builder::ConstBuilder)]
396/// struct SetterCastAttrs {
397///     #[builder(setter(transform = (#[inline] |i: u32| Some(i))))]
398///     value: Option<u32>,
399/// }
400/// ```
401///
402/// ```compile_fail
403/// #[derive(const_builder::ConstBuilder)]
404/// struct SetterCastWrongLifetimes {
405///     #[builder(setter(transform = for<'b> |i: &'a u32| Some(*i)))]
406///     value: Option<u32>,
407/// }
408/// ```
409///
410/// ```compile_fail
411/// #[derive(const_builder::ConstBuilder)]
412/// struct SetterCastConst {
413///     #[builder(setter(transform = const |i: u32| Some(i)))]
414///     value: Option<u32>,
415/// }
416/// ```
417///
418/// ```compile_fail
419/// #[derive(const_builder::ConstBuilder)]
420/// struct SetterCastStatic {
421///     #[builder(setter(transform = static |i: u32| Some(i)))]
422///     value: Option<u32>,
423/// }
424/// ```
425///
426/// ```compile_fail
427/// #[derive(const_builder::ConstBuilder)]
428/// struct SetterCastAsync {
429///     #[builder(setter(transform = async |i: u32| Some(i)))]
430///     value: Option<u32>,
431/// }
432/// ```
433///
434/// ```compile_fail
435/// #[derive(const_builder::ConstBuilder)]
436/// struct SetterCastMove {
437///     #[builder(setter(transform = move |i: u32| Some(i)))]
438///     value: Option<u32>,
439/// }
440/// ```
441///
442/// ```compile_fail
443/// #[derive(const_builder::ConstBuilder)]
444/// struct SetterCastReturnType {
445///     #[builder(setter(transform = |i: u32| -> Option<u32> { Some(i) }))]
446///     value: Option<u32>,
447/// }
448/// ```
449///
450/// ```compile_fail
451/// #[derive(const_builder::ConstBuilder)]
452/// struct SetterCastAndStrip {
453///     #[builder(setter(strip_option, transform = |i: u32| Some(i)))]
454///     value: Option<u32>,
455/// }
456/// ```
457///
458/// ```compile_fail
459/// #[derive(const_builder::ConstBuilder)]
460/// struct SetterCastWrongType {
461///     #[builder(setter(transform = |v: u32| v))]
462///     value: i32,
463/// }
464/// ```
465///
466/// ```compile_fail
467/// #[derive(const_builder::ConstBuilder)]
468/// struct SetterUnknown {
469///     #[builder(setter(strip_result))]
470///     value: Result<u32, u32>,
471/// }
472/// ```
473///
474/// ```compile_fail
475/// #[derive(const_builder::ConstBuilder)]
476/// struct SetterStripOptionNotOption {
477///     #[builder(setter(strip_option))]
478///     value: Result<(), ()>,
479/// }
480/// ```
481///
482/// ```compile_fail
483/// #[derive(const_builder::ConstBuilder)]
484/// struct SetterStripOptionDefault {
485///     #[builder(default, setter(strip_option))]
486///     value: Option<u32>,
487/// }
488/// ```
489fn _compile_fail_test() {}