facet_core/macros.rs
1use crate::{Facet, Opaque, Shape};
2
3/// Helper for the derive macro to infer the shape of a struct field.
4///
5/// This function is never actually called at runtime — it exists purely to let
6/// the compiler infer `TField` from a field accessor closure like `|s: &MyStruct| &s.field`.
7/// By passing a reference to that closure, the compiler resolves `TField` and we can
8/// return `TField::SHAPE` at compile time.
9#[doc(hidden)]
10pub const fn shape_of<'facet, TStruct, TField: Facet<'facet>>(
11 _f: &dyn Fn(&TStruct) -> &TField,
12) -> &'static Shape {
13 TField::SHAPE
14}
15
16/// Helper for the derive macro to infer the shape of an opaque struct field.
17///
18/// Similar to [`shape_of`], but wraps the field type in [`Opaque`] for types that
19/// don't implement `Facet` directly. The closure `|s: &MyStruct| &s.field` lets the
20/// compiler infer `TField`, and we return `Opaque::<TField>::SHAPE`.
21#[doc(hidden)]
22pub const fn shape_of_opaque<'a, TStruct, TField>(
23 _f: &dyn Fn(&TStruct) -> &TField,
24) -> &'static Shape
25where
26 Opaque<TField>: Facet<'a>,
27{
28 Opaque::<TField>::SHAPE
29}
30
31/// Helper for the derive macro to infer the source shape for `#[facet(deserialize_with = ...)]`.
32///
33/// Given a `deserialize_with` function like `fn(&Source) -> Result<Target, E>`, this helper
34/// infers `Source` from the function signature and returns `Source::SHAPE`. This shape is
35/// stored as a [`FieldAttribute::DeserializeFrom`] so the reflection system knows what
36/// intermediate type to construct before calling the conversion function.
37#[doc(hidden)]
38pub const fn shape_of_deserialize_with_source<'facet, Source: Facet<'facet>, Target>(
39 _f: &dyn Fn(&Source) -> Target,
40) -> &'static Shape {
41 Source::SHAPE
42}
43
44/// Helper for the derive macro to infer the target shape for `#[facet(serialize_with = ...)]`.
45///
46/// Given a `serialize_with` function like `fn(&Source) -> Result<Target, &'static str>`, this
47/// helper infers `Target` from the function signature and returns `Target::SHAPE`. This shape
48/// is stored as a [`FieldAttribute::SerializeInto`] so the reflection system knows what
49/// type to serialize instead of the original field type.
50#[doc(hidden)]
51pub const fn shape_of_serialize_with_target<'facet, Source, Target: Facet<'facet>>(
52 _f: &dyn Fn(&Source) -> Result<Target, &'static str>,
53) -> &'static Shape {
54 Target::SHAPE
55}
56
57/// Creates a `ValueVTable` for a given type.
58///
59/// This macro generates a `ValueVTable` with implementations for various traits
60/// (Display, Debug, PartialEq, PartialOrd, Ord, Hash) if they are implemented for the given type.
61///
62/// # Arguments
63///
64/// * `$type_name:ty` - The type for which to create the `ValueVTable`.
65/// * `$type_name_fn:expr` - A function that writes the type name to a formatter.
66///
67/// # Example
68///
69/// ```
70/// use facet_core::value_vtable;
71/// use core::fmt::{self, Formatter};
72/// use facet_core::TypeNameOpts;
73///
74/// let vtable = value_vtable!(String, |f: &mut Formatter<'_>, _opts: TypeNameOpts| write!(f, "String"));
75/// ```
76///
77/// This cannot be used for a generic type because the `impls!` thing depends on type bounds.
78/// If you have a generic type, you need to do specialization yourself, like we do for slices,
79/// arrays, etc. — essentially, this macro is only useful for 1) scalars, 2) inside a derive macro
80#[macro_export]
81macro_rules! value_vtable {
82 ($type_name:ty, $type_name_fn:expr $(,)?) => {
83 const {
84 $crate::ValueVTable::builder::<$type_name>()
85 .type_name($type_name_fn)
86 .display({
87 if $crate::spez::impls!($type_name: core::fmt::Display) {
88 Some(|data: $crate::TypedPtrConst<'_, _>, f| {
89 let data = data.get();
90 use $crate::spez::*;
91 (&&Spez(data)).spez_display(f)
92 })
93 } else {
94 None
95 }
96 })
97 .debug({
98 if $crate::spez::impls!($type_name: core::fmt::Debug) {
99 Some(|data: $crate::TypedPtrConst<'_, _>, f| {
100 let data = data.get();
101 use $crate::spez::*;
102 (&&Spez(data)).spez_debug(f)
103 })
104 } else {
105 None
106 }
107 })
108 .default_in_place({
109 if $crate::spez::impls!($type_name: core::default::Default) {
110 Some(|target: $crate::TypedPtrUninit<'_, _>| unsafe {
111 use $crate::spez::*;
112 $crate::TypedPtrMut::new((&&SpezEmpty::<$type_name>::SPEZ).spez_default_in_place(target.into()).as_mut())
113 })
114 } else {
115 None
116 }
117 })
118 .clone_into({
119 if $crate::spez::impls!($type_name: core::clone::Clone) {
120 Some(|src: $crate::TypedPtrConst<'_, _>, dst: $crate::TypedPtrUninit<'_, _>| unsafe {
121 use $crate::spez::*;
122 let src = src.get();
123 $crate::TypedPtrMut::new((&&Spez(src)).spez_clone_into(dst.into()).as_mut())
124 })
125 } else {
126 None
127 }
128 })
129 .marker_traits({
130 let mut traits = $crate::MarkerTraits::empty();
131 if $crate::spez::impls!($type_name: core::cmp::Eq) {
132 traits = traits.union($crate::MarkerTraits::EQ);
133 }
134 if $crate::spez::impls!($type_name: core::marker::Send) {
135 traits = traits.union($crate::MarkerTraits::SEND);
136 }
137 if $crate::spez::impls!($type_name: core::marker::Sync) {
138 traits = traits.union($crate::MarkerTraits::SYNC);
139 }
140 if $crate::spez::impls!($type_name: core::marker::Copy) {
141 traits = traits.union($crate::MarkerTraits::COPY);
142 }
143 if $crate::spez::impls!($type_name: core::marker::Unpin) {
144 traits = traits.union($crate::MarkerTraits::UNPIN);
145 }
146 if $crate::spez::impls!($type_name: core::panic::UnwindSafe) {
147 traits = traits.union($crate::MarkerTraits::UNWIND_SAFE);
148 }
149 if $crate::spez::impls!($type_name: core::panic::RefUnwindSafe) {
150 traits = traits.union($crate::MarkerTraits::REF_UNWIND_SAFE);
151 }
152
153 traits
154 })
155 .partial_eq({
156 if $crate::spez::impls!($type_name: core::cmp::PartialEq) {
157 Some(|left: $crate::TypedPtrConst<'_, _>, right: $crate::TypedPtrConst<'_, _>| {
158 let left = left.get();
159 let right = right.get();
160 use $crate::spez::*;
161 (&&Spez(left))
162 .spez_partial_eq(&&Spez(right))
163 })
164 } else {
165 None
166 }
167 })
168 .partial_ord({
169 if $crate::spez::impls!($type_name: core::cmp::PartialOrd) {
170 Some(|left: $crate::TypedPtrConst<'_, _>, right: $crate::TypedPtrConst<'_, _>| {
171 let left = left.get();
172 let right = right.get();
173 use $crate::spez::*;
174 (&&Spez(left))
175 .spez_partial_cmp(&&Spez(right))
176 })
177 } else {
178 None
179 }
180 })
181 .ord({
182 if $crate::spez::impls!($type_name: core::cmp::Ord) {
183 Some(|left: $crate::TypedPtrConst<'_, _>, right: $crate::TypedPtrConst<'_, _>| {
184 let left = left.get();
185 let right = right.get();
186 use $crate::spez::*;
187 (&&Spez(left))
188 .spez_cmp(&&Spez(right))
189 })
190 } else {
191 None
192 }
193 })
194 .hash({
195 if $crate::spez::impls!($type_name: core::hash::Hash) {
196 Some(|value: $crate::TypedPtrConst<'_, _>, hasher| {
197 let value = value.get();
198 use $crate::spez::*;
199 (&&Spez(value))
200 .spez_hash(&mut { hasher })
201 })
202 } else {
203 None
204 }
205 })
206 .parse({
207 if $crate::spez::impls!($type_name: core::str::FromStr) {
208 Some(|s, target: $crate::TypedPtrUninit<'_, _>| {
209 use $crate::spez::*;
210 let res = unsafe { (&&SpezEmpty::<$type_name>::SPEZ).spez_parse(s, target.into()) };
211 res.map(|res| unsafe { $crate::TypedPtrMut::new(res.as_mut()) })
212 })
213 } else {
214 None
215 }
216 })
217 .build()
218 }
219 };
220}
221
222/// Creates a `ShapeBuilder` for a given type.
223#[macro_export]
224macro_rules! shape_builder {
225 ($type_name:ty $(,)?) => {
226 const {
227 use $crate::spez::*;
228 SpezEmpty::<$type_name>::BUILDER
229 }
230 };
231}