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<'static> {
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<'static>
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, f| {
52                            use $crate::spez::*;
53                            (&&Spez(data)).spez_display(f)
54                        })
55                    } else {
56                        None
57                    }
58                })
59                .debug(|| {
60                    if $crate::spez::impls!($type_name: core::fmt::Debug) {
61                        Some(|data, f| {
62                            use $crate::spez::*;
63                            (&&Spez(data)).spez_debug(f)
64                        })
65                    } else {
66                        None
67                    }
68                })
69                .default_in_place(|| {
70                    if $crate::spez::impls!($type_name: core::default::Default) {
71                        Some(|target| unsafe {
72                            use $crate::spez::*;
73                            (&&SpezEmpty::<$type_name>::SPEZ).spez_default_in_place(target.into()).as_mut()
74                        })
75                    } else {
76                        None
77                    }
78                })
79                .clone_into(|| {
80                    if $crate::spez::impls!($type_name: core::clone::Clone) {
81                        Some(|src, dst| unsafe {
82                            use $crate::spez::*;
83                            (&&Spez(src)).spez_clone_into(dst.into()).as_mut()
84                        })
85                    } else {
86                        None
87                    }
88                })
89                .marker_traits(|| {
90                    let mut traits = $crate::MarkerTraits::empty();
91                    if $crate::spez::impls!($type_name: core::cmp::Eq) {
92                        traits = traits.union($crate::MarkerTraits::EQ);
93                    }
94                    if $crate::spez::impls!($type_name: core::marker::Send) {
95                        traits = traits.union($crate::MarkerTraits::SEND);
96                    }
97                    if $crate::spez::impls!($type_name: core::marker::Sync) {
98                        traits = traits.union($crate::MarkerTraits::SYNC);
99                    }
100                    if $crate::spez::impls!($type_name: core::marker::Copy) {
101                        traits = traits.union($crate::MarkerTraits::COPY);
102                    }
103                    if $crate::spez::impls!($type_name: core::marker::Unpin) {
104                        traits = traits.union($crate::MarkerTraits::UNPIN);
105                    }
106                    if $crate::spez::impls!($type_name: core::panic::UnwindSafe) {
107                        traits = traits.union($crate::MarkerTraits::UNWIND_SAFE);
108                    }
109                    if $crate::spez::impls!($type_name: core::panic::RefUnwindSafe) {
110                        traits = traits.union($crate::MarkerTraits::REF_UNWIND_SAFE);
111                    }
112
113                    traits
114                })
115                .partial_eq(|| {
116                    if $crate::spez::impls!($type_name: core::cmp::PartialEq) {
117                        Some(|left, right| {
118                            use $crate::spez::*;
119                            (&&Spez(left))
120                                .spez_partial_eq(&&Spez(right))
121                        })
122                    } else {
123                        None
124                    }
125                })
126                .partial_ord(|| {
127                    if $crate::spez::impls!($type_name: core::cmp::PartialOrd) {
128                        Some(|left, right| {
129                            use $crate::spez::*;
130                            (&&Spez(left))
131                                .spez_partial_cmp(&&Spez(right))
132                        })
133                    } else {
134                        None
135                    }
136                })
137                .ord(|| {
138                    if $crate::spez::impls!($type_name: core::cmp::Ord) {
139                        Some(|left, right| {
140                            use $crate::spez::*;
141                            (&&Spez(left))
142                                .spez_cmp(&&Spez(right))
143                        })
144                    } else {
145                        None
146                    }
147                })
148                .hash(|| {
149                    if $crate::spez::impls!($type_name: core::hash::Hash) {
150                        Some(|value, hasher_this, hasher_write_fn| {
151                            use $crate::spez::*;
152                            use $crate::HasherProxy;
153                            (&&Spez(value))
154                                .spez_hash(&mut unsafe { HasherProxy::new(hasher_this, hasher_write_fn) })
155                        })
156                    } else {
157                        None
158                    }
159                })
160                .parse(|| {
161                    if $crate::spez::impls!($type_name: core::str::FromStr) {
162                        Some(|s, target| {
163                            use $crate::spez::*;
164                            let res = unsafe { (&&SpezEmpty::<$type_name>::SPEZ).spez_parse(s, target.into()) };
165                            res.map(|res| unsafe { res.as_mut() })
166                        })
167                    } else {
168                        None
169                    }
170                })
171                .build()
172        }
173    };
174}
175
176/// Similar to `value_vtable!` macro but for `!Sized` types.
177#[macro_export]
178macro_rules! value_vtable_unsized {
179    ($type_name:ty, $type_name_fn:expr) => {
180        const {
181            $crate::ValueVTable::builder_unsized::<$type_name>()
182                .type_name($type_name_fn)
183                .display(|| {
184                    if $crate::spez::impls!($type_name: core::fmt::Display) {
185                        Some(|data, f| {
186                            use $crate::spez::*;
187                            (&&Spez(data)).spez_display(f)
188                        })
189                    } else {
190                        None
191                    }
192                })
193                .debug(|| {
194                    if $crate::spez::impls!($type_name: core::fmt::Debug) {
195                        Some(|data, f| {
196                            use $crate::spez::*;
197                            (&&Spez(data)).spez_debug(f)
198                        })
199                    } else {
200                        None
201                    }
202                })
203                .marker_traits(|| {
204                    let mut traits = $crate::MarkerTraits::empty();
205                    if $crate::spez::impls!($type_name: core::cmp::Eq) {
206                        traits = traits.union($crate::MarkerTraits::EQ);
207                    }
208                    if $crate::spez::impls!($type_name: core::marker::Send) {
209                        traits = traits.union($crate::MarkerTraits::SEND);
210                    }
211                    if $crate::spez::impls!($type_name: core::marker::Sync) {
212                        traits = traits.union($crate::MarkerTraits::SYNC);
213                    }
214                    if $crate::spez::impls!($type_name: core::marker::Copy) {
215                        traits = traits.union($crate::MarkerTraits::COPY);
216                    }
217                    if $crate::spez::impls!($type_name: core::marker::Unpin) {
218                        traits = traits.union($crate::MarkerTraits::UNPIN);
219                    }
220                    if $crate::spez::impls!($type_name: core::panic::UnwindSafe) {
221                        traits = traits.union($crate::MarkerTraits::UNWIND_SAFE);
222                    }
223                    if $crate::spez::impls!($type_name: core::panic::RefUnwindSafe) {
224                        traits = traits.union($crate::MarkerTraits::REF_UNWIND_SAFE);
225                    }
226
227                    traits
228                })
229                .partial_eq(|| {
230                    if $crate::spez::impls!($type_name: core::cmp::PartialEq) {
231                        Some(|left, right| {
232                            use $crate::spez::*;
233                            (&&Spez(left))
234                                .spez_partial_eq(&&Spez(right))
235                        })
236                    } else {
237                        None
238                    }
239                })
240                .partial_ord(|| {
241                    if $crate::spez::impls!($type_name: core::cmp::PartialOrd) {
242                        Some(|left, right| {
243                            use $crate::spez::*;
244                            (&&Spez(left))
245                                .spez_partial_cmp(&&Spez(right))
246                        })
247                    } else {
248                        None
249                    }
250                })
251                .ord(|| {
252                    if $crate::spez::impls!($type_name: core::cmp::Ord) {
253                        Some(|left, right| {
254                            use $crate::spez::*;
255                            (&&Spez(left))
256                                .spez_cmp(&&Spez(right))
257                        })
258                    } else {
259                        None
260                    }
261                })
262                .hash(|| {
263                    if $crate::spez::impls!($type_name: core::hash::Hash) {
264                        Some(|value, hasher_this, hasher_write_fn| {
265                            use $crate::spez::*;
266                            use $crate::HasherProxy;
267                            (&&Spez(value))
268                                .spez_hash(&mut unsafe { HasherProxy::new(hasher_this, hasher_write_fn) })
269                        })
270                    } else {
271                        None
272                    }
273                })
274                .build()
275        }
276    };
277}