facet_core/
macros.rs

1use crate::{Facet, Opaque, Shape};
2
3#[doc(hidden)]
4pub const fn shape_of<'facet, TStruct, TField: Facet<'facet>>(
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, 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            $crate::ValueVTable::builder::<$type_name>()
48                .type_name($type_name_fn)
49                .display({
50                    if $crate::spez::impls!($type_name: core::fmt::Display) {
51                        Some(|data: $crate::TypedPtrConst<'_, _>, f| {
52                            let data = data.get();
53                            use $crate::spez::*;
54                            (&&Spez(data)).spez_display(f)
55                        })
56                    } else {
57                        None
58                    }
59                })
60                .debug({
61                    if $crate::spez::impls!($type_name: core::fmt::Debug) {
62                        Some(|data: $crate::TypedPtrConst<'_, _>, f| {
63                            let data = data.get();
64                            use $crate::spez::*;
65                            (&&Spez(data)).spez_debug(f)
66                        })
67                    } else {
68                        None
69                    }
70                })
71                .default_in_place({
72                    if $crate::spez::impls!($type_name: core::default::Default) {
73                        Some(|target: $crate::TypedPtrUninit<'_, _>| unsafe {
74                            use $crate::spez::*;
75                            $crate::TypedPtrMut::new((&&SpezEmpty::<$type_name>::SPEZ).spez_default_in_place(target.into()).as_mut())
76                        })
77                    } else {
78                        None
79                    }
80                })
81                .clone_into({
82                    if $crate::spez::impls!($type_name: core::clone::Clone) {
83                        Some(|src: $crate::TypedPtrConst<'_, _>, dst: $crate::TypedPtrUninit<'_, _>| unsafe {
84                            use $crate::spez::*;
85                            let src = src.get();
86                            $crate::TypedPtrMut::new((&&Spez(src)).spez_clone_into(dst.into()).as_mut())
87                        })
88                    } else {
89                        None
90                    }
91                })
92                .marker_traits({
93                    let mut traits = $crate::MarkerTraits::empty();
94                    if $crate::spez::impls!($type_name: core::cmp::Eq) {
95                        traits = traits.union($crate::MarkerTraits::EQ);
96                    }
97                    if $crate::spez::impls!($type_name: core::marker::Send) {
98                        traits = traits.union($crate::MarkerTraits::SEND);
99                    }
100                    if $crate::spez::impls!($type_name: core::marker::Sync) {
101                        traits = traits.union($crate::MarkerTraits::SYNC);
102                    }
103                    if $crate::spez::impls!($type_name: core::marker::Copy) {
104                        traits = traits.union($crate::MarkerTraits::COPY);
105                    }
106                    if $crate::spez::impls!($type_name: core::marker::Unpin) {
107                        traits = traits.union($crate::MarkerTraits::UNPIN);
108                    }
109                    if $crate::spez::impls!($type_name: core::panic::UnwindSafe) {
110                        traits = traits.union($crate::MarkerTraits::UNWIND_SAFE);
111                    }
112                    if $crate::spez::impls!($type_name: core::panic::RefUnwindSafe) {
113                        traits = traits.union($crate::MarkerTraits::REF_UNWIND_SAFE);
114                    }
115
116                    traits
117                })
118                .partial_eq({
119                    if $crate::spez::impls!($type_name: core::cmp::PartialEq) {
120                        Some(|left: $crate::TypedPtrConst<'_, _>, right: $crate::TypedPtrConst<'_, _>| {
121                            let left = left.get();
122                            let right = right.get();
123                            use $crate::spez::*;
124                            (&&Spez(left))
125                                .spez_partial_eq(&&Spez(right))
126                        })
127                    } else {
128                        None
129                    }
130                })
131                .partial_ord({
132                    if $crate::spez::impls!($type_name: core::cmp::PartialOrd) {
133                        Some(|left: $crate::TypedPtrConst<'_, _>, right: $crate::TypedPtrConst<'_, _>| {
134                            let left = left.get();
135                            let right = right.get();
136                            use $crate::spez::*;
137                            (&&Spez(left))
138                                .spez_partial_cmp(&&Spez(right))
139                        })
140                    } else {
141                        None
142                    }
143                })
144                .ord({
145                    if $crate::spez::impls!($type_name: core::cmp::Ord) {
146                        Some(|left: $crate::TypedPtrConst<'_, _>, right: $crate::TypedPtrConst<'_, _>| {
147                            let left = left.get();
148                            let right = right.get();
149                            use $crate::spez::*;
150                            (&&Spez(left))
151                                .spez_cmp(&&Spez(right))
152                        })
153                    } else {
154                        None
155                    }
156                })
157                .hash({
158                    if $crate::spez::impls!($type_name: core::hash::Hash) {
159                        Some(|value: $crate::TypedPtrConst<'_, _>, hasher| {
160                            let value = value.get();
161                            use $crate::spez::*;
162                            (&&Spez(value))
163                                .spez_hash(&mut { hasher })
164                        })
165                    } else {
166                        None
167                    }
168                })
169                .parse({
170                    if $crate::spez::impls!($type_name: core::str::FromStr) {
171                        Some(|s, target: $crate::TypedPtrUninit<'_, _>| {
172                            use $crate::spez::*;
173                            let res = unsafe { (&&SpezEmpty::<$type_name>::SPEZ).spez_parse(s, target.into()) };
174                            res.map(|res| unsafe { $crate::TypedPtrMut::new(res.as_mut()) })
175                        })
176                    } else {
177                        None
178                    }
179                })
180                .build()
181        }
182    };
183}
184
185/// Creates a `ShapeBuilder` for a given type.
186#[macro_export]
187macro_rules! shape_builder {
188    ($type_name:ty $(,)?) => {
189        const {
190            use $crate::spez::*;
191            SpezEmpty::<$type_name>::BUILDER
192        }
193    };
194}