facet_core/
macros.rs

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