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}