facet 0.44.4

Reflection for Rust: introspect types at compile time with metadata for serialization, pretty-printing, CLIs, and more
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
#![warn(clippy::std_instead_of_core)]
#![warn(clippy::std_instead_of_alloc)]
//! [![Coverage Status](https://coveralls.io/repos/github/facet-rs/facet/badge.svg?branch=main)](https://coveralls.io/github/facet-rs/facet?branch=main)
//! [![crates.io](https://img.shields.io/crates/v/facet.svg)](https://crates.io/crates/facet)
//! [![documentation](https://docs.rs/facet/badge.svg)](https://docs.rs/facet)
//! [![MIT/Apache-2.0 licensed](https://img.shields.io/crates/l/facet.svg)](./LICENSE)
//! [![Discord](https://img.shields.io/discord/1379550208551026748?logo=discord&label=discord)](https://discord.gg/JhD7CwCJ8F)
//!
//! facet provides reflection for Rust: it gives types a [`SHAPE`](Facet::SHAPE) associated
//! const with details on the layout, fields, doc comments, attributes, etc.
//!
//! It can be used for many things, from (de)serialization to pretty-printing,
//! rich debuggers, CLI parsing, reflection in templating engines, code
//! generation, etc.
//!
//! See <https://facet.rs> for details.
//!
//! # Workspace contents
//!
//! The main `facet` crate re-exports symbols from:
//!
//! - [facet-core](https://github.com/facet-rs/facet/tree/main/facet-core), which defines the main components:
//!   - The [`Facet`] trait and implementations for foreign types (mostly `libstd`)
//!   - The [`Shape`] struct along with various vtables and the whole [`Def`] tree
//!   - Type-erased pointer helpers like [`PtrUninit`], [`PtrConst`], and [`Opaque`]
//!   - Autoderef specialization trick needed for `facet-macros`
//! - [facet-macros](https://github.com/facet-rs/facet/tree/main/facet-macros), which implements the [`Facet`] derive attribute as a fast/light proc macro powered by [unsynn](https://docs.rs/unsynn)
//!
//! For struct manipulation and reflection, we have:
//!
//! - [facet-reflect](https://github.com/facet-rs/facet/tree/main/facet-reflect),
//!   allows building values of arbitrary shapes in safe code, respecting invariants.
//!   It also allows peeking at existing values.
//!
//! Internal crates include:
//!
//! - [facet-testhelpers](https://github.com/facet-rs/facet/tree/main/facet-testhelpers) a simple log logger and color-backtrace configured with the lightweight btparse backend
//!
//! # Ecosystem
//!
//! Various crates live under the <https://github.com/facet-rs> umbrella, and their
//! repositories are kept somewhat-consistent through [facet-dev](https://github.com/facet-rs/facet-dev).
//!
//! Crates are in various states of progress, buyer beware!
//!
//! In terms of data formats, we have:
//!
//! - [facet-json](https://github.com/facet-rs/facet-format/tree/main/facet-json): JSON format support
//! - [facet-toml](https://github.com/facet-rs/facet-format/tree/main/facet-toml): TOML format support
//! - [facet-yaml](https://github.com/facet-rs/facet-format/tree/main/facet-yaml): YAML format support
//! - [facet-msgpack](https://github.com/facet-rs/facet-format/tree/main/facet-msgpack): MessagePack deserialization
//! - [facet-asn1](https://github.com/facet-rs/facet-format/tree/main/facet-asn1): ASN.1 format support
//! - [facet-xdr](https://github.com/facet-rs/facet-format/tree/main/facet-xdr): XDR format support
//! - [facet-csv](https://github.com/facet-rs/facet-format/tree/main/facet-csv): CSV format support
//!
//! Still adjacent to serialization/deserialization, we have:
//!
//! - [facet-urlencoded](https://github.com/facet-rs/facet/tree/main/facet-urlencoded): URL-encoded form data deserialization
//! - [figue](https://github.com/bearcove/figue): CLI arguments, config files, and environment variables (external crate)
//!
//! As far as utilities go:
//!
//! - [facet-value](https://github.com/facet-rs/facet/tree/main/facet-value): Memory-efficient dynamic value type, supporting JSON-like data plus bytes
//! - [facet-pretty](https://github.com/facet-rs/facet/tree/main/facet-pretty): Pretty-print Facet types
//! - [facet-diff](https://github.com/facet-rs/facet/tree/main/facet-diff): Diffing capabilities for Facet types
//! - [facet-assert](https://github.com/facet-rs/facet/tree/main/facet-assert): Pretty assertions for Facet types (no PartialEq required)
//! - [facet-serialize](https://github.com/facet-rs/facet-serialize): Generic iterative serialization facilities
//! - [facet-deserialize](https://github.com/facet-rs/facet-deserialize): Generic iterative deserialization facilities
//!
//! And the less developed:
//!
//! - [facet-inspect](https://github.com/facet-rs/facet-inspect): Utilities to inspect the content of a Facet object
//!
//! # Extended cinematic universe
//!
//! Some crates are developed completely independently from the facet org:
//!
//! - [facet-v8](https://github.com/simonask/facet-v8) provides an experimental Facet/v8 integration
//! - [facet-openapi](https://github.com/ThouCheese/facet-openapi) (experimental) Generates OpenAPI definitions from types that implement Facet
//! - [facet_generate](https://github.com/redbadger/facet-generate) reflects Facet types into Java, Swift and TypeScript
//! - [multi-array-list](https://lib.rs/crates/multi-array-list) provides an experimental `MultiArrayList` type
//!
#![doc = include_str!("../readme-footer.md")]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(builtin_syntax))]
#![cfg_attr(docsrs, feature(prelude_import))]
#![cfg_attr(docsrs, allow(internal_features))]

pub use facet_core::*;

pub use facet_macros::*;

#[cfg(feature = "reflect")]
pub use facet_reflect::*;

/// Built-in facet attributes.
///
/// These attributes are used with the `#[facet(...)]` syntax without a namespace prefix.
/// For example: `#[facet(sensitive)]`, `#[facet(rename = "name")]`, `#[facet(skip)]`.
///
/// Function-based attributes like `default`, `skip_serializing_if`, and `invariants`
/// store type-erased function pointers. The `proxy` attribute stores a Shape reference
/// for custom serialization/deserialization via TryFrom conversions.
pub mod builtin {
    // Re-export function pointer types for grammar variants
    pub use crate::DefaultInPlaceFn;
    pub use crate::InvariantsFn;
    pub use crate::SkipSerializingIfFn;
    pub use crate::TruthyFn;
    pub use crate::ValidatorFn;

    // Generate built-in attribute grammar.
    // Uses empty namespace "" for built-in facet attributes.
    // The `builtin;` flag tells the generator this is inside the facet crate itself,
    // so definition-time code uses `crate::` instead of `::facet::`.
    crate::define_attr_grammar! {
        builtin;
        ns "";
        crate_path ::facet::builtin;

        /// Built-in facet attribute types.
        ///
        /// These represent the runtime-queryable built-in attributes.
        /// Attributes with function pointers store the actual function reference.
        ///
        /// Attributes annotated with `#[storage(flag)]` are stored in `FieldFlags` for O(1) access.
        /// Attributes annotated with `#[storage(field)]` are stored in dedicated `Field` struct fields.
        /// Attributes without `#[storage(...)]` are stored in the `attributes` slice (O(n) lookup).
        /// <https://facet.rs/guide/attributes/>
        pub enum Attr {
            /// Marks a field as containing sensitive data that should be redacted in debug output.
            ///
            /// Usage: `#[facet(sensitive)]`
            #[storage(flag)]
            Sensitive,

            /// Marks a container as opaque - its inner fields don't need to implement Facet.
            ///
            /// Usage: `#[facet(opaque)]`
            Opaque,

            /// Marks a container as transparent - de/serialization is forwarded to the inner type.
            /// Used for newtype patterns.
            ///
            /// Usage: `#[facet(transparent)]`
            Transparent,

            /// Marks a struct as a metadata container - it serializes transparently through
            /// its non-metadata field while preserving metadata for formats that support it.
            ///
            /// Rules:
            /// 1. Exactly one non-metadata field (the "value" field)
            /// 2. At least one metadata field (marked with `#[facet(metadata = "...")]`)
            /// 3. No duplicate metadata kinds
            ///
            /// During serialization, the container is transparent - `Documented<String>` serializes
            /// exactly like `String`. However, formats that support metadata (like Styx) can access
            /// the metadata fields and emit them appropriately (e.g., as doc comments).
            ///
            /// Usage: `#[facet(metadata_container)]`
            ///
            /// # Example
            ///
            /// ```ignore
            /// #[derive(Facet)]
            /// #[facet(metadata_container)]
            /// struct Documented<T> {
            ///     value: T,
            ///     #[facet(metadata = "doc")]
            ///     doc: Option<Vec<String>>,
            /// }
            /// ```
            #[target(container)]
            MetadataContainer,

            /// Marks a field to be flattened into its parent structure.
            ///
            /// Usage: `#[facet(flatten)]`
            #[storage(flag)]
            Flatten,

            /// Marks an opaque payload field as structurally trailing in its container.
            ///
            /// This enables formats that support it to treat the field as "remaining bytes"
            /// instead of requiring an outer length frame.
            ///
            /// Usage: `#[facet(trailing)]`
            #[target(field)]
            Trailing,

            /// Marks a field as a child node (for hierarchical formats like XML).
            ///
            /// Usage: `#[facet(child)]`
            #[storage(flag)]
            Child,

            /// Denies unknown fields during deserialization.
            ///
            /// Usage: `#[facet(deny_unknown_fields)]`
            DenyUnknownFields,

            /// Uses the default value when the field is missing during deserialization.
            /// Stores a function pointer that produces the default value in-place.
            ///
            /// Usage: `#[facet(default)]` (uses Default trait) or `#[facet(default = expr)]`
            ///
            /// When no explicit value is given (`#[facet(default)]`), the Rust field type's
            /// `Default::default()` is used. This requires the field type to implement Default.
            /// For opaque fields, this uses the underlying Rust type's Default, not the
            /// Facet shape's default.
            ///
            /// Note: The HAS_DEFAULT flag is also set when this attribute is present.
            Default(make_t or $ty::default()),

            /// Skips both serialization and deserialization of this field.
            ///
            /// Usage: `#[facet(skip)]`
            #[storage(flag)]
            Skip,

            /// Skips serialization of this field.
            ///
            /// Usage: `#[facet(skip_serializing)]`
            #[storage(flag)]
            SkipSerializing,

            /// Conditionally skips serialization based on a predicate function.
            /// Stores a type-erased function pointer: `fn(PtrConst) -> bool`.
            ///
            /// Usage: `#[facet(skip_serializing_if = is_empty)]`
            SkipSerializingIf(predicate SkipSerializingIfFn),

            /// Skips serialization unless the value is truthy.
            /// Uses the type's registered truthiness predicate when available.
            ///
            /// Usage: `#[facet(skip_unless_truthy)]`
            SkipUnlessTruthy,

            /// Skips deserialization of this field (uses default value).
            ///
            /// Usage: `#[facet(skip_deserializing)]`
            #[storage(flag)]
            SkipDeserializing,

            /// For enums: variants are serialized without a discriminator tag.
            ///
            /// Usage: `#[facet(untagged)]`
            Untagged,

            /// Marks an enum variant as a catch-all for unknown variant names.
            /// When deserializing, if no variant matches the input tag,
            /// the variant marked with `other` will be used.
            ///
            /// Usage: `#[facet(other)]`
            Other,

            /// Serializes/Deserializers enum to/from integer based on variant discriminant.
            ///
            /// Usage: `#[facet(is_numeric)]`
            IsNumeric,

            /// Marks an enum as having cow-like semantics (Borrowed/Owned variants).
            ///
            /// When deserializing into a cow-like enum and borrowing is not available
            /// (e.g., from JSON), the deserializer automatically selects the `Owned` variant
            /// instead of the `Borrowed` variant. This allows types like `Stem<'a>` to be
            /// deserialized from formats that cannot provide borrowed data.
            ///
            /// Requirements:
            /// - The enum must have exactly 2 variants named `Borrowed` and `Owned`
            /// - `Borrowed` typically contains a reference type (e.g., `&'a str`)
            /// - `Owned` contains an owned equivalent (e.g., `String`, `CompactString`)
            ///
            /// Usage: `#[facet(cow)]`
            ///
            /// # Example
            ///
            /// ```ignore
            /// #[derive(Facet)]
            /// #[facet(cow)]
            /// #[repr(u8)]
            /// pub enum Stem<'a> {
            ///     Borrowed(&'a str),
            ///     Owned(CompactString),
            /// }
            /// ```
            #[target(container)]
            Cow,

            /// Marks a type as Plain Old Data.
            ///
            /// POD types have no invariants - any combination of valid field values
            /// produces a valid instance. This enables safe mutation through reflection
            /// (poke operations).
            ///
            /// Usage: `#[facet(pod)]`
            Pod,

            /// Renames a field or variant during serialization/deserialization.
            ///
            /// Usage: `#[facet(rename = "new_name")]`
            #[storage(field)]
            Rename(&'static str),

            /// Renames all fields/variants using a case conversion rule.
            ///
            /// Usage: `#[facet(rename_all = "camelCase")]`
            ///
            /// Supported rules: camelCase, snake_case, PascalCase, SCREAMING_SNAKE_CASE,
            /// kebab-case, SCREAMING-KEBAB-CASE
            RenameAll(&'static str),

            /// Aliases a field or variant during deserialization.
            ///
            /// Usage: `#[facet(alias = "additional_name")]`
            ///
            /// Allows for deserializing a field from either the alias or the original name.
            #[storage(field)]
            Alias(&'static str),

            /// Tag attribute with dual usage:
            ///
            /// **Container-level (with value):** For internally/adjacently tagged enums,
            /// specifies the field name for the discriminator tag.
            ///
            /// Usage: `#[facet(tag = "type")]`
            ///
            /// **Field-level (without value):** Within an `#[facet(other)]` variant,
            /// marks a field as capturing the variant tag name when deserializing
            /// self-describing formats that emit VariantTag events.
            ///
            /// Usage: `#[facet(tag)]` on a String field
            Tag(Option<&'static str>),

            /// Content attribute with dual usage:
            ///
            /// **Container-level (with value):** For adjacently tagged enums,
            /// specifies the field name for the variant content.
            ///
            /// Usage: `#[facet(content = "data")]`
            ///
            /// **Field-level (without value):** Within an `#[facet(other)]` variant,
            /// marks a field as capturing the variant payload when deserializing
            /// self-describing formats that emit VariantTag events.
            ///
            /// Usage: `#[facet(content)]` on a field
            Content(Option<&'static str>),

            /// Identifies the type with a tag for self-describing formats.
            ///
            /// Usage: `#[facet(type_tag = "com.example.MyType")]`
            TypeTag(&'static str),

            /// Type invariant validation function.
            /// Stores a type-erased function pointer: `fn(PtrConst) -> bool`.
            ///
            /// Usage: `#[facet(invariants = validate_fn)]`
            Invariants(predicate InvariantsFn),

            /// Declares the truthiness predicate for this container type.
            /// Stores a type-erased function pointer: `fn(PtrConst) -> bool`.
            ///
            /// Usage: `#[facet(truthy = Self::is_truthy)]`
            Truthy(predicate TruthyFn),

            /// Applies `skip_unless_truthy` to every field in the container.
            ///
            /// Usage: `#[facet(skip_all_unless_truthy)]`
            SkipAllUnlessTruthy,

            /// Proxy type for serialization and deserialization.
            /// The proxy type must implement `TryFrom<ProxyType> for FieldType` (for deserialization)
            /// and `TryFrom<&FieldType> for ProxyType` (for serialization).
            ///
            /// Usage: `#[facet(proxy = MyProxyType)]`
            Proxy(shape_type),

            /// Marks a field as having a recursive type that needs lazy shape resolution.
            ///
            /// Use this on fields where the type recursively contains the parent type,
            /// such as `Vec<Self>`, `Box<Self>`, `Option<Arc<Self>>`, etc.
            ///
            /// Without this attribute, such recursive types would cause a compile-time cycle.
            /// With this attribute, the field's shape is resolved lazily via a closure.
            ///
            /// Usage: `#[facet(recursive_type)]`
            ///
            /// # Example
            ///
            /// ```ignore
            /// #[derive(Facet)]
            /// struct Node {
            ///     value: i32,
            ///     #[facet(recursive_type)]
            ///     children: Vec<Node>,
            /// }
            /// ```
            RecursiveType,

            // Note: `traits(...)` and `bound` are compile-time-only directives
            // processed by the derive macro. They are not stored as runtime attributes.
            // See DeclaredTraits in facet-macros-impl/src/parsed.rs for their handling.

            /// Adds custom trait bounds to the generated Facet impl.
            /// The bounds are added to the where clause alongside auto-generated bounds.
            ///
            /// Usage: `#[facet(where T: Clone + Send)]`
            ///
            /// When you need a type parameter to implement Facet (e.g., for proxy types),
            /// use a higher-ranked trait bound: `#[facet(where T: for<'f> Facet<'f>)]`
            ///
            /// If HRTB is too restrictive, you can use the internal lifetime `'ʄ` directly:
            /// `#[facet(where T: Facet<'ʄ>)]` (note: `'ʄ` is internal and may change).
            Where(&'static str),

            /// Adds custom traits to the generated Facet impl.
            ///
            /// Usage: `#[facet(traits(Trait1, Trait2))]`
            ///
            /// When you need a type parameter to implement Facet (e.g., for proxy types),
            /// use a higher-ranked trait bound: `#[facet(traits(for<'f> Facet<'f>))]`
            ///
            /// If HRTB is too restrictive, you can use the internal lifetime `'ʄ` directly:
            /// `#[facet(traits(Facet<'ʄ>))]` (note: `'ʄ` is internal and may change).
            Traits(&'static str),

            /// Automatically identifies which traits are implemented by the type.
            AutoTraits,

            /// Adds metadata to the annotated field.
            Metadata(&'static str),

            /// Specifies `facet`'s path in case it's not in the default location.
            Crate(&'static str),

            // Note: `from_ref` and `try_from_ref` are compile-time-only directives
            // processed by the derive macro. They are not stored as runtime attributes.
            // They generate a `try_from` function in the VTable.
            // The derive macro reads these from raw PFacetAttr tokens, not from Attr values.
            // The reference type is inferred from the function signature.

            /// Infallible constructor from a reference type.
            /// The function must have signature `fn(&'a R) -> Self` where R is the source type.
            ///
            /// Usage: `#[facet(from_ref = Self::from_ref)]`
            ///
            /// Note: This is compile-time only. The path is read from raw tokens by the derive macro.
            FromRef(arbitrary),

            /// Fallible constructor from a reference type.
            /// The function must have signature `fn(&'a R) -> Result<Self, E>` where R is the source type.
            ///
            /// Usage: `#[facet(try_from_ref = Self::try_from_ref)]`
            ///
            /// Note: This is compile-time only. The path is read from raw tokens by the derive macro.
            TryFromRef(arbitrary),

            // ================================================================
            // DOM-related attributes (for XML/HTML serialization)
            // ================================================================

            /// Marks a field as an XML/HTML attribute on the element tag.
            ///
            /// Usage: `#[facet(attribute)]`
            ///
            /// Fields marked as attributes are serialized as XML/HTML element attributes
            /// rather than child elements or text content.
            Attribute,

            /// Marks a field as text content within an XML/HTML element.
            ///
            /// Usage: `#[facet(text)]`
            ///
            /// Fields marked as text contain the text content of the element,
            /// as opposed to child elements or attributes.
            Text,

            /// Marks an enum variant as a catch-all for custom/unknown elements.
            ///
            /// Usage: `#[facet(custom_element)]`
            ///
            /// When deserializing XML/HTML, unknown element tags are captured
            /// by the variant marked with `custom_element`.
            CustomElement
        }
    }

    // Manual Facet impl for Attr since we can't use the derive macro inside the facet crate.
    // This is a simplified opaque implementation.
    unsafe impl crate::Facet<'_> for Attr {
        const SHAPE: &'static crate::Shape = &crate::Shape {
            id: crate::Shape::id_of::<Self>(),
            decl_id: crate::DeclId::new(crate::decl_id_hash("@facet#enum#Attr")),
            layout: crate::Shape::layout_of::<Self>(),
            vtable: crate::VTableErased::Direct(&crate::VTableDirect::empty()),
            type_ops: None,
            marker_traits: crate::MarkerTraits::empty(),
            type_identifier: "facet::builtin::Attr",
            module_path: None, // Foreign type, no module path available
            source_file: None,
            source_line: None,
            source_column: None,
            ty: crate::Type::User(crate::UserType::Opaque),
            def: crate::Def::Undefined,
            type_params: &[],
            const_params: &[],
            doc: &[],
            attributes: &[],
            type_tag: None,
            inner: None,
            builder_shape: None,
            type_name: None,
            proxy: None,
            format_proxies: &[],
            opaque_adapter: None,
            variance: crate::VarianceDesc::BIVARIANT,
            flags: crate::ShapeFlags::empty(),
            tag: None,
            content: None,
            rename: None,
        };
    }
}

#[cfg(feature = "static_assertions")]
pub use static_assertions;

/// Define an attribute grammar with type-safe parsing.
///
/// This macro generates:
/// - The attribute types (enum + structs)
/// - A `__parse_attr!` macro for parsing attribute tokens
/// - Re-exports for the necessary proc-macros
///
/// # Example
///
/// ```ignore
/// facet::define_attr_grammar! {
///     pub enum Attr {
///         /// Skip this field entirely
///         Skip,
///         /// Rename to a different name
///         Rename(&'static str),
///         /// Database column configuration
///         Column(Column),
///     }
///
///     pub struct Column {
///         /// Override the database column name
///         pub name: Option<&'static str>,
///         /// Mark as primary key
///         pub primary_key: bool,
///     }
/// }
/// ```
///
/// This generates an `Attr` enum and `Column` struct with the specified fields,
/// along with a `__parse_attr!` macro that can parse attribute syntax like:
///
/// - `skip` → `Attr::Skip`
/// - `rename("users")` → `Attr::Rename("users")`
/// - `column(name = "user_id", primary_key)` → `Attr::Column(Column { name: Some("user_id"), primary_key: true })`
///
/// # Supported Field Types
///
/// | Grammar Type | Rust Type | Syntax |
/// |--------------|-----------|--------|
/// | `bool` | `bool` | `flag` or `flag = true` |
/// | `&'static str` | `&'static str` | `name = "value"` |
/// | `Option<&'static str>` | `Option<&'static str>` | `name = "value"` (optional) |
/// | `Option<bool>` | `Option<bool>` | `flag = true` (optional) |
#[macro_export]
macro_rules! define_attr_grammar {
    ($($grammar:tt)*) => {
        $crate::__make_parse_attr! { $($grammar)* }
    };
}