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