facet_core/_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/// Creates a `ValueVTable` for a given type.
9///
10/// This macro generates a `ValueVTable` with implementations for various traits
11/// (Display, Debug, PartialEq, Eq, PartialOrd, Ord, Hash) if they are implemented for the given type.
12///
13/// # Arguments
14///
15/// * `$type_name:ty` - The type for which to create the `ValueVTable`.
16/// * `$type_name_fn:expr` - A function that writes the type name to a formatter.
17///
18/// # Example
19///
20/// ```
21/// use facet_core::value_vtable;
22/// use core::fmt::{self, Formatter};
23/// use facet_core::TypeNameOpts;
24///
25/// let vtable = value_vtable!(String, |f: &mut Formatter<'_>, _opts: TypeNameOpts| write!(f, "String"));
26/// ```
27///
28/// This cannot be used for a generic type because the `impls!` thing depends on type bounds.
29/// If you have a generic type, you need to do specialization yourself, like we do for slices,
30/// arrays, etc. — essentially, this macro is only useful for 1) scalars, 2) inside a derive macro
31#[macro_export]
32macro_rules! value_vtable {
33    ($type_name:ty, $type_name_fn:expr) => {
34        &const {
35            let mut builder = $crate::ValueVTable::builder()
36                .type_name($type_name_fn)
37                .drop_in_place(|data| unsafe { data.drop_in_place::<$type_name>() });
38
39            if $crate::spez::impls!($type_name: core::fmt::Display) {
40                builder = builder.display(|data, f| {
41                    use $crate::spez::*;
42                    (&&Spez(unsafe { data.as_ref::<$type_name>() })).spez_display(f)
43                });
44            }
45
46            if $crate::spez::impls!($type_name: core::fmt::Debug) {
47                builder = builder.debug(|data, f| {
48                    use $crate::spez::*;
49                    (&&Spez(unsafe { data.as_ref::<$type_name>() })).spez_debug(f)
50                });
51            }
52
53            if $crate::spez::impls!($type_name: core::default::Default) {
54                builder = builder.default_in_place(|target| {
55                    use $crate::spez::*;
56                    unsafe { (&&SpezEmpty::<$type_name>::SPEZ).spez_default_in_place(target) }
57                });
58            }
59
60            if $crate::spez::impls!($type_name: core::clone::Clone) {
61                builder = builder.clone_into(|src, dst| {
62                    use $crate::spez::*;
63                    unsafe { (&&Spez(src.as_ref::<$type_name>())).spez_clone_into(dst) }
64                });
65            }
66
67            {
68                let mut traits = $crate::MarkerTraits::empty();
69                if $crate::spez::impls!($type_name: core::cmp::Eq) {
70                    traits = traits.union($crate::MarkerTraits::EQ);
71                }
72                if $crate::spez::impls!($type_name: core::marker::Send) {
73                    traits = traits.union($crate::MarkerTraits::SEND);
74                }
75                if $crate::spez::impls!($type_name: core::marker::Sync) {
76                    traits = traits.union($crate::MarkerTraits::SYNC);
77                }
78                if $crate::spez::impls!($type_name: core::marker::Copy) {
79                    traits = traits.union($crate::MarkerTraits::COPY);
80                }
81                builder = builder.marker_traits(traits);
82            }
83
84            if $crate::spez::impls!($type_name: core::cmp::PartialEq) {
85                builder = builder.eq(|left, right| {
86                    use $crate::spez::*;
87                    (&&Spez(unsafe { left.as_ref::<$type_name>() }))
88                        .spez_eq(&&Spez(unsafe { right.as_ref::<$type_name>() }))
89                });
90            }
91
92            if $crate::spez::impls!($type_name: core::cmp::PartialOrd) {
93                builder = builder.partial_ord(|left, right| {
94                    use $crate::spez::*;
95                    (&&Spez(unsafe { left.as_ref::<$type_name>() }))
96                        .spez_partial_cmp(&&Spez(unsafe { right.as_ref::<$type_name>() }))
97                });
98            }
99
100            if $crate::spez::impls!($type_name: core::cmp::Ord) {
101                builder = builder.ord(|left, right| {
102                    use $crate::spez::*;
103                    (&&Spez(unsafe { left.as_ref::<$type_name>() }))
104                        .spez_cmp(&&Spez(unsafe { right.as_ref::<$type_name>() }))
105                });
106            }
107
108            if $crate::spez::impls!($type_name: core::hash::Hash) {
109                builder = builder.hash(|value, hasher_this, hasher_write_fn| {
110                    use $crate::spez::*;
111                    use $crate::HasherProxy;
112                    (&&Spez(unsafe { value.as_ref::<$type_name>() }))
113                        .spez_hash(&mut unsafe { HasherProxy::new(hasher_this, hasher_write_fn) })
114                });
115            }
116
117            if $crate::spez::impls!($type_name: core::str::FromStr) {
118                builder = builder.parse(|s, target| {
119                    use $crate::spez::*;
120                    let res = unsafe { (&&SpezEmpty::<$type_name>::SPEZ).spez_parse(s, target) };
121                    res.map(|_| unsafe { target.assume_init() })
122                });
123            }
124
125            builder.build()
126        }
127    };
128}