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    pub enum Attr {
58        /// Mark an enum variant as the default.
59        ///
60        /// Usage: `#[facet(default::variant)]`
61        Variant,
62    }
63}
64
65// ============================================================================
66// PLUGIN TEMPLATE
67// ============================================================================
68
69/// Plugin chain entry point.
70///
71/// Called by `#[derive(Facet)]` when `#[facet(derive(Default))]` is present.
72#[macro_export]
73macro_rules! __facet_invoke {
74    (
75        @tokens { $($tokens:tt)* }
76        @remaining { $($remaining:tt)* }
77        @plugins { $($plugins:tt)* }
78        @facet_crate { $($facet_crate:tt)* }
79    ) => {
80        $crate::__facet_invoke_internal! {
81            @tokens { $($tokens)* }
82            @remaining { $($remaining)* }
83            @plugins {
84                $($plugins)*
85                @plugin {
86                    @name { "Default" }
87                    @template {
88                        impl ::core::default::Default for @Self {
89                            fn default() -> Self {
90                                @if_struct {
91                                    Self {
92                                        @for_field {
93                                            @field_name: @field_default_expr,
94                                        }
95                                    }
96                                }
97                                @if_enum {
98                                    @for_variant {
99                                        @if_attr(default::variant) {
100                                            Self::@variant_name @variant_default_construction
101                                        }
102                                    }
103                                }
104                            }
105                        }
106                    }
107                }
108            }
109            @facet_crate { $($facet_crate)* }
110        }
111    };
112}
113
114/// Internal macro that either chains to next plugin or calls finalize
115#[doc(hidden)]
116#[macro_export]
117macro_rules! __facet_invoke_internal {
118    // No more plugins - call finalize
119    (
120        @tokens { $($tokens:tt)* }
121        @remaining { }
122        @plugins { $($plugins:tt)* }
123        @facet_crate { $($facet_crate:tt)* }
124    ) => {
125        $($facet_crate)*::__facet_finalize! {
126            @tokens { $($tokens)* }
127            @plugins { $($plugins)* }
128            @facet_crate { $($facet_crate)* }
129        }
130    };
131
132    // More plugins - chain to next
133    (
134        @tokens { $($tokens:tt)* }
135        @remaining { $next:path $(, $rest:path)* $(,)? }
136        @plugins { $($plugins:tt)* }
137        @facet_crate { $($facet_crate:tt)* }
138    ) => {
139        $next! {
140            @tokens { $($tokens)* }
141            @remaining { $($rest),* }
142            @plugins { $($plugins)* }
143            @facet_crate { $($facet_crate)* }
144        }
145    };
146}