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 must be attributed with
38//! `#[builder(unsized_tail)]` to replace the field drop code with an assert
39//! that the field cannot be dropped. Functionally, this combination of packed,
40//! unsized tails, and with the builder requirements means that this field has
41//! to be [`ManuallyDrop<T: ?Sized>`](std::mem::ManuallyDrop) or a wrapper
42//! around it.
43//!
44//! `enum` and `union` types are unsupported.
45//!
46//! # Default Values
47//!
48//! Fields can be attributed with `#[builder(default = None)]` or similar to
49//! be made optional by providing a default value.
50//!
51//! This default value will _not_ be dropped if it is overridden or the builder
52//! is dropped. Consequently, the value should be something that does not need
53//! to be dropped, such as a primitive, [`None`], [`String::new()`],
54//! [`Vec::new()`], [`Cow::Borrowed`](std::borrow::Cow), or similar.
55//!
56//! # API Stability
57//!
58//! The API of the emitted builder is considered forward-compatible as long as
59//! no fields are removed (even when private but not if its setter was already
60//! private) unless care is taken to ensure the surface area to consumers stays
61//! the same, and the changes don't already constitute as breaking to consumers
62//! of the original struct.
63//!
64//! Adding the `default` attribute to the struct or field is forward-compatible.
65//! Removing the attribute is a breaking change.
66//!
67//! Additionally, changes to builder attributes that lead to reduction in
68//! visibility, renames, removal, or changes in signature of functions in the
69//! emitted code are also breaking changes. This includes attributes such `vis`,
70//! `rename`, `rename_fn`, and `setter`.
71//!
72//! Major versions of this crate may also introduce breaking changes to the
73//! emitted structs. Minor versions will ensure to emit forward-compatible code.
74//!
75//! # Unchecked Builder
76//!
77//! There is also an `*UncheckedBuilder` without safety checks, which is private
78//! by default. While similar to the checked builder at a glance, not every
79//! attribute applies to it in the same way (f.e. the `setter` attribute has no
80//! effect), and its API isn't considered stable across source struct
81//! modifications, so it should not be exposed in stable public interfaces.
82//!
83//! This struct is used to simplify the implementation of the checked builder
84//! and it is exposed for users that want additional control.
85//!
86//! This builder works broadly in the same way as the checked builder, however:
87//!
88//! - initialized fields aren't tracked,
89//! - setting fields that were already set will forget the old value,
90//! - calling `build` is unsafe due to the lack of tracking, and
91//! - dropping it will forget all field values that were already set.
92//!
93//! You can convert between the checked and unchecked builder with
94//! `*Builder::into_unchecked` and `*UncheckedBuilder::assert_init`.
95//!
96//! # Example
97//!
98//! ```
99//! use const_builder::ConstBuilder;
100//!
101//! #[derive(ConstBuilder)]
102//! # #[derive(Debug, PartialEq)]
103//! pub struct Person<'a> {
104//!     // fields are required by default
105//!     pub name: &'a str,
106//!     // optional fields have a default specified
107//!     // the value is required even when the type implements `Default`!
108//!     #[builder(default = 0)]
109//!     pub age: u32,
110//! }
111//!
112//! let steve = const {
113//!     Person::builder()
114//!         .name("steve smith")
115//!         .build()
116//! };
117//! # assert_eq!(
118//! #     steve,
119//! #     Person {
120//! #         name: "steve smith",
121//! #         age: 0,
122//! #     }
123//! # );
124//! ```
125//!
126//! # Generated Interface
127//!
128//! The example above would generate an interface similar to the following. The
129//! actual generated code is more complex because it includes bounds to ensure
130//! fields are only written once and that the struct is fully initialized when
131//! calling `build`.
132//!
133//! ```
134//! # // This isn't an example to run, just an example "shape".
135//! # _ = stringify!(
136//! /// A builder type for [`Person`].
137//! pub struct PersonBuilder<'a, const _NAME: bool = false, const _AGE: bool = false> { ... }
138//!
139//! impl<'a, ...> PersonBuilder<'a, ...> {
140//!     /// Creates a new builder.
141//!     pub const fn new() -> Self;
142//!
143//!     /// Returns the finished value.
144//!     ///
145//!     /// This function can only be called when all required fields have been set.
146//!     pub const fn build(self) -> Person<'a>;
147//!
148//!     // one setter function per field
149//!     pub const fn name(self, value: &'a str) -> PersonBuilder<'a, ...>;
150//!     pub const fn age(self, value: u32) -> PersonBuilder<'a, ...>;
151//!
152//!     /// Unwraps this builder into its unsafe counterpart.
153//!     ///
154//!     /// This isn't unsafe in itself, however using it carelessly may lead to
155//!     /// leaking objects and not dropping initialized values.
156//!     const fn into_unchecked(self) -> PersonUncheckedBuilder<'a>;
157//! }
158//!
159//! impl<'a> Person<'a> {
160//!     /// Creates a new builder for this type.
161//!     pub const fn builder() -> PersonBuilder<'a>;
162//! }
163//!
164//! /// An _unchecked_ builder type for [`Person`].
165//! ///
166//! /// This version being _unchecked_ means it has less safety guarantees:
167//! /// - No tracking is done whether fields are initialized, so [`Self::build`] is `unsafe`.
168//! /// - If dropped, already initialized fields will be leaked.
169//! /// - The same field can be set multiple times. If done, the old value will be leaked.
170//! struct PersonUncheckedBuilder<'a> { ... }
171//!
172//! impl<'a> PersonUncheckedBuilder<'a> {
173//!    /// Creates a new unchecked builder.
174//!    pub const fn new() -> Self;
175//!
176//!    /// Asserts that the fields specified by the const generics as well as all optional
177//!    /// fields are initialized and promotes this value into a checked builder.
178//!    ///
179//!    /// # Safety
180//!    ///
181//!    /// The fields whose const generic are `true` and all optional fields have to be
182//!    /// initialized.
183//!    ///
184//!    /// Optional fields are initialized by [`Self::new`] by default, however using
185//!    /// [`Self::as_uninit`] allows de-initializing them. This means that this function
186//!    /// isn't even necessarily safe to call if all const generics are `false`.
187//!    pub const unsafe fn assert_init<const _NAME: bool, const _AGE: bool>(self) -> PersonBuilder<'a, _NAME, _AGE>;
188//!
189//!    /// Returns the finished value.
190//!    ///
191//!    /// # Safety
192//!    ///
193//!    /// This function requires that all fields have been initialized.
194//!    pub const unsafe fn build(self) -> Person<'a>;
195//!
196//!    // one setter function per field
197//!    pub const fn name(mut self, value: &'a str) -> Self;
198//!    pub const fn age(mut self, value: u32) -> Self;
199//!
200//!    /// Gets a mutable reference to the partially initialized data.
201//!    pub const fn as_uninit(&mut self) -> &mut ::core::mem::MaybeUninit<Person<'a>>;
202//! }
203//! # );
204//! ```
205//!
206//! # Struct Attributes
207//!
208//! These attributes can be specified within `#[builder(...)]` on the struct
209//! level.
210//!
211//! | Attribute                   | Meaning |
212//! |:--------------------------- |:------- |
213//! | `default`                   | Generate a const-compatible `*::default()` function and [`Default`] derive. Requires every field to have a default value. |
214//! | `vis = "$vis"`              | Change the visibility of the builder type. May be an empty string for private. Default is the same as the struct. |
215//! | `rename = $name`            | Renames the builder type. Defaults to "`<Type>Builder`". |
216//! | `rename_fn = $name`         | Renames the associated function that creates the builder. Defaults to `builder`. Set to `false` to disable. |
217//! | `unchecked(vis = "$vis")`   | Change the visibility of the unchecked builder type. Default is private. |
218//! | `unchecked(rename = $name)` | Renames the unchecked builder type. Defaults to "`<Type>UncheckedBuilder`". |
219//!
220//! # Field Attributes
221//!
222//! These attributes can be specified within `#[builder(...)]` on the struct's
223//! fields.
224//!
225//! | Attribute                      | Meaning |
226//! |:------------------------------ |:------- |
227//! | `vis = "$vis"`                 | Change the visibility of the builder's field setter. May be an empty string for private. Default is `pub`. |
228//! | `default = $value`             | Make the field optional by providing a default value. The value must be evaluatable in `const`. |
229//! | `rename = $name`               | Renames the setters for this field. Defaults to the field name. |
230//! | `rename_generic = $name`       | Renames the name of the associated const generic. Defaults to "`_{field:upper}`". |
231//! | `leak_on_drop`                 | Instead of dropping the field when dropping the builder, do nothing. |
232//! | `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. |
233//! | `setter(transform = $closure)` | Accepts closure syntax. The setter is changed to accept its inputs and set the corresponding value to its output. Parameter types are required. The closure body must be evaluatable in `const`. |
234//! | `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))`. |
235//!
236//! # Attributes Example
237//!
238//! ```
239//! use const_builder::ConstBuilder;
240//!
241//! #[derive(ConstBuilder)]
242//! // change the builder from pub (same as Person) to crate-internal
243//! // also override the name of the builder to `CreatePerson`
244//! #[builder(vis = "pub(crate)", rename = "CreatePerson")]
245//! // change the unchecked builder from priv also to crate-internal
246//! #[builder(unchecked(vis = "pub(crate)"))]
247//! # #[derive(Debug, PartialEq)]
248//! pub struct Person<'a> {
249//!     // required field with public setter
250//!     name: &'a str,
251//!     // optional field with public setter
252//!     #[builder(default = 0)]
253//!     age: u32,
254//!     // optional field with private setter
255//!     #[builder(default = 1, vis = "" /* priv */)]
256//!     version: u32,
257//! }
258//!
259//! # assert_eq!(
260//! #     const {
261//! #         Person::builder()
262//! #             .name("smith")
263//! #             .build()
264//! #     },
265//! #     Person {
266//! #         name: "smith",
267//! #         age: 0,
268//! #         version: 1,
269//! #     }
270//! # );
271//! ```
272//!
273//! [nomicon section on unchecked uninitialized memory]: https://doc.rust-lang.org/nomicon/unchecked-uninit.html
274
275#![forbid(unsafe_code)]
276#![warn(clippy::doc_markdown)]
277
278use proc_macro::TokenStream;
279use syn::{DeriveInput, parse_macro_input};
280
281mod const_builder_impl;
282mod model;
283mod util;
284
285/// Generates the builder types for the attributed struct.
286///
287/// See the crate-level documentation for more details.
288#[proc_macro_derive(ConstBuilder, attributes(builder))]
289pub fn derive_const_builder(input: TokenStream) -> TokenStream {
290    let input = parse_macro_input!(input as DeriveInput);
291    const_builder_impl::entry_point(input).into()
292}
293
294/// I considered UI tests but since we still emit the code on almost all errors,
295/// there are a bunch of rustc diagnostics mixed in (when the compile error
296/// isn't literally just a rustc error). These aren't stable, so those tests
297/// would just break between language versions -- or even just stable and
298/// nightly.
299///
300/// ```compile_fail
301/// #[derive(const_builder::ConstBuilder)]
302/// struct TupleStruct(u32, u64);
303/// ```
304///
305/// ```compile_fail
306/// #[derive(const_builder::ConstBuilder)]
307/// struct UnitStruct;
308/// ```
309///
310/// ```compile_fail
311/// #[derive(const_builder::ConstBuilder)]
312/// enum Enum {
313///     B { a: u32, b: u64 },
314/// }
315/// ```
316///
317/// ```compile_fail
318/// #[derive(const_builder::ConstBuilder)]
319/// union Union {
320///     a: u32,
321///     b: u64,
322/// }
323/// ```
324///
325/// ```compile_fail
326/// #[derive(const_builder::ConstBuilder)]
327/// #[builder(default)]
328/// struct InvalidDefault {
329///     a: u32,
330///     #[builder(default = 0)]
331///     b: u32,
332/// }
333/// ```
334///
335/// ```compile_fail
336/// #[derive(const_builder::ConstBuilder)]
337/// struct DefaultNoValue {
338///     #[builder(default)]
339///     a: u32,
340/// }
341/// ```
342///
343/// ```compile_fail
344/// #[derive(const_builder::ConstBuilder)]
345/// struct WrongUnsizedTailPosition {
346///     #[builder(unsized_tail)]
347///     a: u32,
348///     b: u32,
349/// }
350/// ```
351///
352/// ```compile_fail
353/// // on stable, the macro code will not compile due to `UnsizedField: Sized`
354/// // bounds. however on nightly with `trivial_bounds`, the actual output of
355/// // the macro will compile, but the bounds will still prevent instantiating
356/// // or otherwise using the builder.
357/// // see also: https://github.com/rust-lang/rust/issues/48214
358/// #[derive(const_builder::ConstBuilder)]
359/// struct UnsizedField {
360///     a: [u32],
361/// }
362///
363/// // ensure instantiating fails anyways
364/// _ = UnsizedFieldBuilder::new();
365/// ```
366///
367/// ```compile_fail
368/// // this test actually fails for two reasons:
369/// // - rust disallowing possible-Drop unsized tails in packed structs
370/// // - static assert when a packed struct's `unsized_tail` field `needs_drop`
371/// #[derive(const_builder::ConstBuilder)]
372/// #[repr(Rust, packed)]
373/// struct PackedUnsizedDropTail<T: ?Sized> {
374///     #[builder(unsized_tail)]
375///     a: T,
376/// }
377///
378/// // ensure a variant with a `needs_drop` tail is instantiated
379/// _ = PackedUnsizedDropTail::<String>::builder();
380/// ```
381///
382/// ```compile_fail
383/// #[derive(const_builder::ConstBuilder)]
384/// struct SetterCastNoClosure {
385///     #[builder(setter(transform))]
386///     value: Option<u32>,
387/// }
388/// ```
389///
390/// ```compile_fail
391/// #[derive(const_builder::ConstBuilder)]
392/// struct SetterCastNotAClosure1 {
393///     #[builder(setter(transform = r#""hello""#))]
394///     value: Option<u32>,
395/// }
396/// ```
397///
398/// ```compile_fail
399/// #[derive(const_builder::ConstBuilder)]
400/// struct SetterCastNotAClosure2 {
401///     #[builder(setter(transform = 42))]
402///     value: Option<u32>,
403/// }
404/// ```
405///
406/// ```compile_fail
407/// #[derive(const_builder::ConstBuilder)]
408/// struct SetterCastNotAClosure3 {
409///     #[builder(setter(transform = Some(42)))]
410///     value: Option<u32>,
411/// }
412/// ```
413///
414/// ```compile_fail
415/// #[derive(const_builder::ConstBuilder)]
416/// struct SetterCastNoType {
417///     #[builder(setter(transform = |i| Some(i)))]
418///     value: Option<u32>,
419/// }
420/// ```
421///
422/// ```compile_fail
423/// #[derive(const_builder::ConstBuilder)]
424/// struct SetterCastNoTypePartial1 {
425///     #[builder(setter(transform = |a: u32, b| a + b))]
426///     value: u32,
427/// }
428/// ```
429///
430/// ```compile_fail
431/// #[derive(const_builder::ConstBuilder)]
432/// struct SetterCastNoTypePartial2 {
433///     #[builder(setter(transform = |a, b: u32| a + b))]
434///     value: u32,
435/// }
436/// ```
437///
438/// ```compile_fail
439/// // `works.rs` contains a similar case that compiles
440/// #[derive(ConstBuilder)]
441/// struct SetterCastPatNoType {
442///     #[builder(setter(transform = |Wrap(v)| v))]
443///     value: u32,
444/// }
445///
446/// struct Wrap<T>(T);
447/// ```
448///
449/// ```compile_fail
450/// #[derive(const_builder::ConstBuilder)]
451/// struct SetterCastAttrs {
452///     #[builder(setter(transform = (#[inline] |i: u32| Some(i))))]
453///     value: Option<u32>,
454/// }
455/// ```
456///
457/// ```compile_fail
458/// #[derive(const_builder::ConstBuilder)]
459/// struct SetterCastWrongLifetimes {
460///     #[builder(setter(transform = for<'b> |i: &'a u32| Some(*i)))]
461///     value: Option<u32>,
462/// }
463/// ```
464///
465/// ```compile_fail
466/// #[derive(const_builder::ConstBuilder)]
467/// struct SetterCastConst {
468///     #[builder(setter(transform = const |i: u32| Some(i)))]
469///     value: Option<u32>,
470/// }
471/// ```
472///
473/// ```compile_fail
474/// #[derive(const_builder::ConstBuilder)]
475/// struct SetterCastStatic {
476///     #[builder(setter(transform = static |i: u32| Some(i)))]
477///     value: Option<u32>,
478/// }
479/// ```
480///
481/// ```compile_fail
482/// #[derive(const_builder::ConstBuilder)]
483/// struct SetterCastAsync {
484///     #[builder(setter(transform = async |i: u32| Some(i)))]
485///     value: Option<u32>,
486/// }
487/// ```
488///
489/// ```compile_fail
490/// #[derive(const_builder::ConstBuilder)]
491/// struct SetterCastMove {
492///     #[builder(setter(transform = move |i: u32| Some(i)))]
493///     value: Option<u32>,
494/// }
495/// ```
496///
497/// ```compile_fail
498/// #[derive(const_builder::ConstBuilder)]
499/// struct SetterCastReturnType {
500///     #[builder(setter(transform = |i: u32| -> Option<u32> { Some(i) }))]
501///     value: Option<u32>,
502/// }
503/// ```
504///
505/// ```compile_fail
506/// #[derive(const_builder::ConstBuilder)]
507/// struct SetterCastAndStrip {
508///     #[builder(setter(strip_option, transform = |i: u32| Some(i)))]
509///     value: Option<u32>,
510/// }
511/// ```
512///
513/// ```compile_fail
514/// #[derive(const_builder::ConstBuilder)]
515/// struct SetterCastWrongType {
516///     #[builder(setter(transform = |v: u32| v))]
517///     value: i32,
518/// }
519/// ```
520///
521/// ```compile_fail
522/// #[derive(const_builder::ConstBuilder)]
523/// struct SetterUnknown {
524///     #[builder(setter(strip_result))]
525///     value: Result<u32, u32>,
526/// }
527/// ```
528///
529/// ```compile_fail
530/// #[derive(const_builder::ConstBuilder)]
531/// struct SetterStripOptionNotOption {
532///     #[builder(setter(strip_option))]
533///     value: Result<(), ()>,
534/// }
535/// ```
536///
537/// ```compile_fail
538/// #[derive(const_builder::ConstBuilder)]
539/// struct SetterStripOptionDefault {
540///     #[builder(default, setter(strip_option))]
541///     value: Option<u32>,
542/// }
543/// ```
544///
545/// ```compile_fail
546/// use core::marker::PhantomData;
547///
548/// #[derive(const_builder::ConstBuilder)]
549/// struct InvalidUse<T = u32> {
550///     #[builder(default = PhantomData)]
551///     marker: PhantomData<T>,
552/// }
553///
554/// // fails because it can't infer the generic type
555/// let value = InvalidUse::builder().build();
556/// ```
557///
558/// ```compile_fail
559/// #[derive(const_builder::ConstBuilder)]
560/// struct Incomplete1 {
561///     unset: bool,
562/// }
563///
564/// let value = Incomplete1::builder().build();
565/// ```
566///
567/// ```compile_fail
568/// #[derive(const_builder::ConstBuilder)]
569/// struct Incomplete2 {
570///     #[builder(default = false)]
571///     defaulted: bool,
572///     unset: bool,
573/// }
574///
575/// let value = Incomplete2::builder().build();
576/// ```
577///
578/// ```compile_fail
579/// #[derive(const_builder::ConstBuilder)]
580/// struct Incomplete3 {
581///     set: bool,
582///     unset: bool,
583/// }
584///
585/// let value = Incomplete3::builder().set(true).build();
586/// ```
587///
588/// ```compile_fail
589/// #[derive(const_builder::ConstBuilder)]
590/// struct DuplicateSet {
591///     field: bool,
592/// }
593///
594/// DuplicateSet::builder().field(true).field(true);
595/// ```
596fn _compile_fail_test() {}