Skip to main content

facet_default/
lib.rs

1//! # facet-default
2//!
3//! Derive [`Default`] for your types using facet's plugin system with custom field defaults.
4//!
5//! ## Usage
6//!
7//! ```ignore
8//! use facet::Facet;
9//! use facet_default as _;
10//!
11//! #[derive(Facet, Debug)]
12//! #[facet(derive(Default))]
13//! pub struct Config {
14//!     #[facet(default = "localhost")]
15//!     host: String,
16//!     #[facet(default = 8080u16)]
17//!     port: u16,
18//!     // No attribute = uses Default::default()
19//!     debug: bool,
20//! }
21//! ```
22//!
23//! ## Attributes
24//!
25//! ### Field Level
26//!
27//! - `#[facet(default = literal)]` - Use a literal value
28//! - `#[facet(default)]` - Use `Default::default()` for the field type
29//!
30//! Fields without attributes use `Default::default()`.
31//!
32//! ## Enums
33//!
34//! For enums, mark the default variant:
35//!
36//! ```ignore
37//! #[derive(Facet, Debug)]
38//! #[facet(derive(Default))]
39//! #[repr(u8)]
40//! pub enum Status {
41//!     #[facet(default::variant)]
42//!     Pending,
43//!     Active,
44//!     Done,
45//! }
46//! ```
47
48// ============================================================================
49// ATTRIBUTE GRAMMAR
50// ============================================================================
51
52facet::define_attr_grammar! {
53    ns "default";
54    crate_path ::facet_default;
55
56    /// Default attribute types for configuring Default implementation.
57    #[non_exhaustive]
58    pub enum Attr {
59        /// Mark an enum variant as the default.
60        ///
61        /// Usage: `#[facet(default::variant)]`
62        Variant,
63    }
64}
65
66// ============================================================================
67// PLUGIN TEMPLATE
68// ============================================================================
69
70/// Plugin chain entry point.
71///
72/// Called by `#[derive(Facet)]` when `#[facet(derive(Default))]` is present.
73#[macro_export]
74macro_rules! __facet_invoke {
75    (
76        @tokens { $($tokens:tt)* }
77        @remaining { $($remaining:tt)* }
78        @plugins { $($plugins:tt)* }
79        @facet_crate { $($facet_crate:tt)* }
80    ) => {
81        $crate::__facet_invoke_internal! {
82            @tokens { $($tokens)* }
83            @remaining { $($remaining)* }
84            @plugins {
85                $($plugins)*
86                @plugin {
87                    @name { "Default" }
88                    @template {
89                        impl ::core::default::Default for @Self {
90                            fn default() -> Self {
91                                @if_struct {
92                                    Self {
93                                        @for_field {
94                                            @field_name: @field_default_expr,
95                                        }
96                                    }
97                                }
98                                @if_enum {
99                                    @for_variant {
100                                        @if_attr(default::variant) {
101                                            Self::@variant_name @variant_default_construction
102                                        }
103                                    }
104                                }
105                            }
106                        }
107                    }
108                }
109            }
110            @facet_crate { $($facet_crate)* }
111        }
112    };
113}
114
115/// Internal macro that either chains to next plugin or calls finalize
116#[doc(hidden)]
117#[macro_export]
118macro_rules! __facet_invoke_internal {
119    // No more plugins - call finalize
120    (
121        @tokens { $($tokens:tt)* }
122        @remaining { }
123        @plugins { $($plugins:tt)* }
124        @facet_crate { $($facet_crate:tt)* }
125    ) => {
126        $($facet_crate)*::__facet_finalize! {
127            @tokens { $($tokens)* }
128            @plugins { $($plugins)* }
129            @facet_crate { $($facet_crate)* }
130        }
131    };
132
133    // More plugins - chain to next
134    (
135        @tokens { $($tokens:tt)* }
136        @remaining { $next:path $(, $rest:path)* $(,)? }
137        @plugins { $($plugins:tt)* }
138        @facet_crate { $($facet_crate:tt)* }
139    ) => {
140        $next! {
141            @tokens { $($tokens)* }
142            @remaining { $($rest),* }
143            @plugins { $($plugins)* }
144            @facet_crate { $($facet_crate)* }
145        }
146    };
147}