facet/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![warn(missing_docs)]
3#![warn(clippy::std_instead_of_core)]
4#![warn(clippy::std_instead_of_alloc)]
5#![doc = include_str!("../README.md")]
6#![cfg_attr(docsrs, feature(doc_cfg))]
7#![cfg_attr(docsrs, feature(builtin_syntax))]
8#![cfg_attr(docsrs, feature(prelude_import))]
9#![cfg_attr(docsrs, allow(internal_features))]
10
11pub use facet_core::*;
12
13pub use facet_macros::*;
14
15#[cfg(feature = "reflect")]
16pub use facet_reflect::*;
17
18/// Built-in facet attributes.
19///
20/// These attributes are used with the `#[facet(...)]` syntax without a namespace prefix.
21/// For example: `#[facet(sensitive)]`, `#[facet(rename = "name")]`, `#[facet(skip)]`.
22///
23/// Function-based attributes like `default`, `skip_serializing_if`, and `invariants`
24/// store type-erased function pointers. The `proxy` attribute stores a Shape reference
25/// for custom serialization/deserialization via TryFrom conversions.
26pub mod builtin {
27    // Re-export function pointer types for grammar variants
28    pub use crate::DefaultInPlaceFn;
29    pub use crate::InvariantsFn;
30    pub use crate::SkipSerializingIfFn;
31    pub use crate::TruthyFn;
32    pub use crate::ValidatorFn;
33
34    // Generate built-in attribute grammar.
35    // Uses empty namespace "" for built-in facet attributes.
36    // The `builtin;` flag tells the generator this is inside the facet crate itself,
37    // so definition-time code uses `crate::` instead of `::facet::`.
38    crate::define_attr_grammar! {
39        builtin;
40        ns "";
41        crate_path ::facet::builtin;
42
43        /// Built-in facet attribute types.
44        ///
45        /// These represent the runtime-queryable built-in attributes.
46        /// Attributes with function pointers store the actual function reference.
47        ///
48        /// Attributes annotated with `#[storage(flag)]` are stored in `FieldFlags` for O(1) access.
49        /// Attributes annotated with `#[storage(field)]` are stored in dedicated `Field` struct fields.
50        /// Attributes without `#[storage(...)]` are stored in the `attributes` slice (O(n) lookup).
51        /// <https://facet.rs/guide/attributes/>
52        pub enum Attr {
53            /// Marks a field as containing sensitive data that should be redacted in debug output.
54            ///
55            /// Usage: `#[facet(sensitive)]`
56            #[storage(flag)]
57            Sensitive,
58
59            /// Marks a container as opaque - its inner fields don't need to implement Facet.
60            ///
61            /// Usage: `#[facet(opaque)]`
62            Opaque,
63
64            /// Marks a container as transparent - de/serialization is forwarded to the inner type.
65            /// Used for newtype patterns.
66            ///
67            /// Usage: `#[facet(transparent)]`
68            Transparent,
69
70            /// Marks a field to be flattened into its parent structure.
71            ///
72            /// Usage: `#[facet(flatten)]`
73            #[storage(flag)]
74            Flatten,
75
76            /// Marks a field as a child node (for hierarchical formats like KDL/XML).
77            ///
78            /// Usage: `#[facet(child)]`
79            #[storage(flag)]
80            Child,
81
82            /// Denies unknown fields during deserialization.
83            ///
84            /// Usage: `#[facet(deny_unknown_fields)]`
85            DenyUnknownFields,
86
87            /// Uses the default value when the field is missing during deserialization.
88            /// Stores a function pointer that produces the default value in-place.
89            ///
90            /// Usage: `#[facet(default)]` (uses Default trait) or `#[facet(default = expr)]`
91            ///
92            /// When no explicit value is given (`#[facet(default)]`), the Rust field type's
93            /// `Default::default()` is used. This requires the field type to implement Default.
94            /// For opaque fields, this uses the underlying Rust type's Default, not the
95            /// Facet shape's default.
96            ///
97            /// Note: The HAS_DEFAULT flag is also set when this attribute is present.
98            Default(make_t or $ty::default()),
99
100            /// Skips both serialization and deserialization of this field.
101            ///
102            /// Usage: `#[facet(skip)]`
103            #[storage(flag)]
104            Skip,
105
106            /// Skips serialization of this field.
107            ///
108            /// Usage: `#[facet(skip_serializing)]`
109            #[storage(flag)]
110            SkipSerializing,
111
112            /// Conditionally skips serialization based on a predicate function.
113            /// Stores a type-erased function pointer: `fn(PtrConst) -> bool`.
114            ///
115            /// Usage: `#[facet(skip_serializing_if = is_empty)]`
116            SkipSerializingIf(predicate SkipSerializingIfFn),
117
118            /// Skips serialization unless the value is truthy.
119            /// Uses the type's registered truthiness predicate when available.
120            ///
121            /// Usage: `#[facet(skip_unless_truthy)]`
122            SkipUnlessTruthy,
123
124            /// Skips deserialization of this field (uses default value).
125            ///
126            /// Usage: `#[facet(skip_deserializing)]`
127            #[storage(flag)]
128            SkipDeserializing,
129
130            /// For enums: variants are serialized without a discriminator tag.
131            ///
132            /// Usage: `#[facet(untagged)]`
133            Untagged,
134
135            /// Serializes/Deserializers enum to/from integer based on variant discriminant.
136            ///
137            /// Usage: `#[facet(is_numeric)]`
138            IsNumeric,
139
140            /// Marks a type as Plain Old Data.
141            ///
142            /// POD types have no invariants - any combination of valid field values
143            /// produces a valid instance. This enables safe mutation through reflection
144            /// (poke operations).
145            ///
146            /// Usage: `#[facet(pod)]`
147            Pod,
148
149            /// Renames a field or variant during serialization/deserialization.
150            ///
151            /// Usage: `#[facet(rename = "new_name")]`
152            #[storage(field)]
153            Rename(&'static str),
154
155            /// Renames all fields/variants using a case conversion rule.
156            ///
157            /// Usage: `#[facet(rename_all = "camelCase")]`
158            ///
159            /// Supported rules: camelCase, snake_case, PascalCase, SCREAMING_SNAKE_CASE,
160            /// kebab-case, SCREAMING-KEBAB-CASE
161            RenameAll(&'static str),
162
163            /// Aliases a field or variant during deserialization.
164            ///
165            /// Usage: `#[facet(alias = "additional_name")]`
166            ///
167            /// Allows for deserializing a field from either the alias or the original name.
168            #[storage(field)]
169            Alias(&'static str),
170
171            /// For internally/adjacently tagged enums: the field name for the tag.
172            ///
173            /// Usage: `#[facet(tag = "type")]`
174            Tag(&'static str),
175
176            /// For adjacently tagged enums: the field name for the content.
177            ///
178            /// Usage: `#[facet(content = "data")]`
179            Content(&'static str),
180
181            /// Identifies the type with a tag for self-describing formats.
182            ///
183            /// Usage: `#[facet(type_tag = "com.example.MyType")]`
184            TypeTag(&'static str),
185
186            /// Type invariant validation function.
187            /// Stores a type-erased function pointer: `fn(PtrConst) -> bool`.
188            ///
189            /// Usage: `#[facet(invariants = validate_fn)]`
190            Invariants(predicate InvariantsFn),
191
192            /// Declares the truthiness predicate for this container type.
193            /// Stores a type-erased function pointer: `fn(PtrConst) -> bool`.
194            ///
195            /// Usage: `#[facet(truthy = Self::is_truthy)]`
196            Truthy(predicate TruthyFn),
197
198            /// Applies `skip_unless_truthy` to every field in the container.
199            ///
200            /// Usage: `#[facet(skip_all_unless_truthy)]`
201            SkipAllUnlessTruthy,
202
203            /// Proxy type for serialization and deserialization.
204            /// The proxy type must implement `TryFrom<ProxyType> for FieldType` (for deserialization)
205            /// and `TryFrom<&FieldType> for ProxyType` (for serialization).
206            ///
207            /// Usage: `#[facet(proxy = MyProxyType)]`
208            Proxy(shape_type),
209
210            /// Marks a field as having a recursive type that needs lazy shape resolution.
211            ///
212            /// Use this on fields where the type recursively contains the parent type,
213            /// such as `Vec<Self>`, `Box<Self>`, `Option<Arc<Self>>`, etc.
214            ///
215            /// Without this attribute, such recursive types would cause a compile-time cycle.
216            /// With this attribute, the field's shape is resolved lazily via a closure.
217            ///
218            /// Usage: `#[facet(recursive_type)]`
219            ///
220            /// # Example
221            ///
222            /// ```ignore
223            /// #[derive(Facet)]
224            /// struct Node {
225            ///     value: i32,
226            ///     #[facet(recursive_type)]
227            ///     children: Vec<Node>,
228            /// }
229            /// ```
230            RecursiveType,
231
232            // Note: `traits(...)` and `auto_traits` are compile-time-only directives
233            // processed by the derive macro. They are not stored as runtime attributes.
234            // See DeclaredTraits in facet-macros-impl/src/parsed.rs for their handling.
235        }
236    }
237
238    // Manual Facet impl for Attr since we can't use the derive macro inside the facet crate.
239    // This is a simplified opaque implementation.
240    unsafe impl crate::Facet<'_> for Attr {
241        const SHAPE: &'static crate::Shape = &crate::Shape {
242            id: crate::Shape::id_of::<Self>(),
243            layout: crate::Shape::layout_of::<Self>(),
244            vtable: crate::VTableErased::Direct(&crate::VTableDirect::empty()),
245            type_ops: None,
246            marker_traits: crate::MarkerTraits::empty(),
247            type_identifier: "facet::builtin::Attr",
248            ty: crate::Type::User(crate::UserType::Opaque),
249            def: crate::Def::Undefined,
250            type_params: &[],
251            doc: &[],
252            attributes: &[],
253            type_tag: None,
254            inner: None,
255            builder_shape: None,
256            type_name: None,
257            proxy: None,
258            variance: crate::Variance::COVARIANT,
259            flags: crate::ShapeFlags::empty(),
260            tag: None,
261            content: None,
262        };
263    }
264}
265
266#[cfg(feature = "static_assertions")]
267pub use static_assertions;
268
269/// Define an attribute grammar with type-safe parsing.
270///
271/// This macro generates:
272/// - The attribute types (enum + structs)
273/// - A `__parse_attr!` macro for parsing attribute tokens
274/// - Re-exports for the necessary proc-macros
275///
276/// # Example
277///
278/// ```ignore
279/// facet::define_attr_grammar! {
280///     pub enum Attr {
281///         /// Skip this field entirely
282///         Skip,
283///         /// Rename to a different name
284///         Rename(&'static str),
285///         /// Database column configuration
286///         Column(Column),
287///     }
288///
289///     pub struct Column {
290///         /// Override the database column name
291///         pub name: Option<&'static str>,
292///         /// Mark as primary key
293///         pub primary_key: bool,
294///     }
295/// }
296/// ```
297///
298/// This generates an `Attr` enum and `Column` struct with the specified fields,
299/// along with a `__parse_attr!` macro that can parse attribute syntax like:
300///
301/// - `skip` → `Attr::Skip`
302/// - `rename("users")` → `Attr::Rename("users")`
303/// - `column(name = "user_id", primary_key)` → `Attr::Column(Column { name: Some("user_id"), primary_key: true })`
304///
305/// # Supported Field Types
306///
307/// | Grammar Type | Rust Type | Syntax |
308/// |--------------|-----------|--------|
309/// | `bool` | `bool` | `flag` or `flag = true` |
310/// | `&'static str` | `&'static str` | `name = "value"` |
311/// | `Option<&'static str>` | `Option<&'static str>` | `name = "value"` (optional) |
312/// | `Option<bool>` | `Option<bool>` | `flag = true` (optional) |
313#[macro_export]
314macro_rules! define_attr_grammar {
315    ($($grammar:tt)*) => {
316        $crate::__make_parse_attr! { $($grammar)* }
317    };
318}