facet_trait/
macros.rs

1use crate::{Facet, Shape};
2
3#[doc(hidden)]
4pub const fn shape_of<TStruct, TField: Facet>(_f: &dyn Fn(TStruct) -> TField) -> &'static Shape {
5    TField::SHAPE
6}
7
8#[doc(hidden)]
9#[macro_export]
10macro_rules! struct_field {
11    ($struct:ty, $field:tt) => {
12        $crate::Field::builder()
13            .name(stringify!($field))
14            .shape($crate::shape_of(&|s: $struct| s.$field))
15            .offset(::core::mem::offset_of!($struct, $field))
16            .flags($crate::FieldFlags::EMPTY)
17            .build()
18    };
19}
20
21#[doc(hidden)]
22#[macro_export]
23macro_rules! struct_fields {
24    ($struct:ty, ($($field:tt),*)) => {{
25        static FIELDS: &[$crate::Field] = &[ $($crate::struct_field!($struct, $field)),* ];
26        FIELDS
27    }};
28}
29
30#[doc(hidden)]
31#[macro_export]
32macro_rules! enum_unit_variant {
33    ($enum:ty, $variant:ident) => {
34        $crate::Variant {
35            name: stringify!($variant),
36            discriminant: None,
37            kind: $crate::VariantKind::Unit,
38        }
39    };
40    ($enum:ty, $variant:ident, $discriminant:expr) => {
41        $crate::Variant {
42            name: stringify!($variant),
43            discriminant: Some($discriminant),
44            kind: $crate::VariantKind::Unit,
45        }
46    };
47}
48
49#[doc(hidden)]
50#[macro_export]
51macro_rules! enum_tuple_variant {
52    ($enum:ty, $variant:ident, [$($field_type:ty),*]) => {{
53        static FIELDS: &[$crate::Field] = &[
54            $(
55                $crate::Field {
56                    name: concat!("_", stringify!($field_type)),
57                    shape_fn: <$field_type>::shape,
58                    offset: 0, // Will be calculated at runtime
59                    flags: $crate::FieldFlags::EMPTY,
60                }
61            ),*
62        ];
63
64        $crate::Variant {
65            name: stringify!($variant),
66            discriminant: None,
67            kind: $crate::VariantKind::Tuple { fields: FIELDS },
68        }
69    }};
70    ($enum:ty, $variant:ident, [$($field_type:ty),*], $discriminant:expr) => {{
71        static FIELDS: &[$crate::Field] = &[
72            $(
73                $crate::Field {
74                    name: concat!("_", stringify!($field_type)),
75                    shape_fn: <$field_type>::shape,
76                    offset: 0, // Will be calculated at runtime
77                    flags: $crate::FieldFlags::EMPTY,
78                }
79            ),*
80        ];
81
82        $crate::Variant {
83            name: stringify!($variant),
84            discriminant: Some($discriminant),
85            kind: $crate::VariantKind::Tuple { fields: FIELDS },
86        }
87    }};
88}
89
90#[doc(hidden)]
91#[macro_export]
92macro_rules! enum_struct_variant {
93    ($enum:ty, $variant:ident, {$($field:ident: $field_type:ty),*}) => {{
94        static FIELDS: &[$crate::Field] = &[
95            $(
96                $crate::Field {
97                    name: stringify!($field),
98                    shape_fn: <$field_type>::shape,
99                    offset: 0, // Will be calculated at runtime
100                    flags: $crate::FieldFlags::EMPTY,
101                }
102            ),*
103        ];
104
105        $crate::Variant {
106            name: stringify!($variant),
107            discriminant: None,
108            kind: $crate::VariantKind::Struct { fields: FIELDS },
109        }
110    }};
111    ($enum:ty, $variant:ident, {$($field:ident: $field_type:ty),*}, $discriminant:expr) => {{
112        static FIELDS: &[$crate::Field] = &[
113            $(
114                $crate::Field {
115                    name: stringify!($field),
116                    shape_fn: <$field_type>::shape,
117                    offset: 0, // Will be calculated at runtime
118                    flags: $crate::FieldFlags::EMPTY,
119                }
120            ),*
121        ];
122
123        $crate::Variant {
124            name: stringify!($variant),
125            discriminant: Some($discriminant),
126            kind: $crate::VariantKind::Struct { fields: FIELDS },
127        }
128    }};
129}
130
131#[doc(hidden)]
132#[macro_export]
133macro_rules! enum_variants {
134    ($enum:ty, [$($variant:expr),*]) => {{
135        static VARIANTS: &[$crate::Variant] = &[ $($variant),* ];
136        VARIANTS
137    }};
138}
139
140/// Creates a `ValueVTable` for a given type.
141///
142/// This macro generates a `ValueVTable` with implementations for various traits
143/// (Display, Debug, PartialEq, Eq, PartialOrd, Ord, Hash) if they are implemented for the given type.
144///
145/// # Arguments
146///
147/// * `$type_name:ty` - The type for which to create the `ValueVTable`.
148/// * `$type_name_fn:expr` - A function that writes the type name to a formatter.
149///
150/// # Example
151///
152/// ```
153/// use facet_trait::value_vtable;
154/// use core::fmt::{self, Formatter};
155/// use facet_types::TypeNameOpts;
156///
157/// let vtable = value_vtable!(String, |f: &mut Formatter<'_>, _opts: TypeNameOpts| write!(f, "String"));
158/// ```
159///
160/// This cannot be used for a generic type because the `impls!` thing depends on type bounds.
161/// If you have a generic type, you need to do specialization yourself, like we do for slices,
162/// arrays, etc. — essentially, this macro is only useful for 1) scalars, 2) inside a derive macro
163#[macro_export]
164macro_rules! value_vtable {
165    ($type_name:ty, $type_name_fn:expr) => {
166        &const {
167            let mut builder = $crate::ValueVTable::builder()
168                .type_name($type_name_fn)
169                .drop_in_place(|data| unsafe { data.drop_in_place::<$type_name>() });
170
171            if $crate::facet_spez::impls!($type_name: core::fmt::Display) {
172                builder = builder.display(|data, f| {
173                    use $crate::facet_spez::*;
174                    (&&Spez(unsafe { data.as_ref::<$type_name>() })).spez_display(f)
175                });
176            }
177
178            if $crate::facet_spez::impls!($type_name: core::fmt::Debug) {
179                builder = builder.debug(|data, f| {
180                    use $crate::facet_spez::*;
181                    (&&Spez(unsafe { data.as_ref::<$type_name>() })).spez_debug(f)
182                });
183            }
184
185            if $crate::facet_spez::impls!($type_name: core::default::Default) {
186                builder = builder.default_in_place(|target| {
187                    use $crate::facet_spez::*;
188                    (&&Spez(<$type_name as $crate::Facet>::ARCHETYPE)).spez_default_in_place(target)
189                });
190            }
191
192            if $crate::facet_spez::impls!($type_name: core::clone::Clone) {
193                builder = builder.clone_into(|src, dst| {
194                    use $crate::facet_spez::*;
195                    (&&Spez(unsafe { src.as_ref::<$type_name>() })).spez_clone_into(dst)
196                });
197            }
198
199            {
200                let mut traits = $crate::MarkerTraits::empty();
201                if $crate::facet_spez::impls!($type_name: core::cmp::Eq) {
202                    traits = traits.union($crate::MarkerTraits::EQ);
203                }
204                if $crate::facet_spez::impls!($type_name: core::marker::Send) {
205                    traits = traits.union($crate::MarkerTraits::SEND);
206                }
207                if $crate::facet_spez::impls!($type_name: core::marker::Sync) {
208                    traits = traits.union($crate::MarkerTraits::SYNC);
209                }
210                if $crate::facet_spez::impls!($type_name: core::marker::Copy) {
211                    traits = traits.union($crate::MarkerTraits::COPY);
212                }
213                builder = builder.marker_traits(traits);
214            }
215
216            if $crate::facet_spez::impls!($type_name: core::cmp::PartialEq) {
217                builder = builder.eq(|left, right| {
218                    use $crate::facet_spez::*;
219                    (&&Spez(unsafe { left.as_ref::<$type_name>() }))
220                        .spez_eq(&&Spez(unsafe { right.as_ref::<$type_name>() }))
221                });
222            }
223
224            if $crate::facet_spez::impls!($type_name: core::cmp::PartialOrd) {
225                builder = builder.partial_ord(|left, right| {
226                    use $crate::facet_spez::*;
227                    (&&Spez(unsafe { left.as_ref::<$type_name>() }))
228                        .spez_partial_cmp(&&Spez(unsafe { right.as_ref::<$type_name>() }))
229                });
230            }
231
232            if $crate::facet_spez::impls!($type_name: core::cmp::Ord) {
233                builder = builder.ord(|left, right| {
234                    use $crate::facet_spez::*;
235                    (&&Spez(unsafe { left.as_ref::<$type_name>() }))
236                        .spez_cmp(&&Spez(unsafe { right.as_ref::<$type_name>() }))
237                });
238            }
239
240            if $crate::facet_spez::impls!($type_name: core::hash::Hash) {
241                builder = builder.hash(|value, hasher_this, hasher_write_fn| {
242                    use $crate::facet_spez::*;
243                    use $crate::HasherProxy;
244                    (&&Spez(unsafe { value.as_ref::<$type_name>() }))
245                        .spez_hash(&mut unsafe { HasherProxy::new(hasher_this, hasher_write_fn) })
246                });
247            }
248
249            builder.build()
250        }
251    };
252}