facet_core/impls_core/
scalar.rs

1use crate::value_vtable;
2use crate::*;
3use core::num::NonZero;
4use typeid::ConstTypeId;
5
6unsafe impl Facet<'_> for ConstTypeId {
7    const VTABLE: &'static ValueVTable = &const {
8        value_vtable!(ConstTypeId, |f, _opts| write!(
9            f,
10            "{}",
11            Self::SHAPE.type_identifier
12        ))
13    };
14
15    const SHAPE: &'static Shape = &const {
16        Shape::builder_for_sized::<Self>()
17            .type_identifier("ConstTypeId")
18            .def(Def::Scalar)
19            .ty(Type::User(UserType::Opaque))
20            .build()
21    };
22}
23
24unsafe impl Facet<'_> for core::any::TypeId {
25    const VTABLE: &'static ValueVTable = &const {
26        value_vtable!(core::any::TypeId, |f, _opts| write!(
27            f,
28            "{}",
29            Self::SHAPE.type_identifier
30        ))
31    };
32
33    const SHAPE: &'static Shape = &const {
34        Shape::builder_for_sized::<Self>()
35            .type_identifier("TypeId")
36            .def(Def::Scalar)
37            .ty(Type::User(UserType::Opaque))
38            .build()
39    };
40}
41
42unsafe impl Facet<'_> for () {
43    const VTABLE: &'static ValueVTable = &const { value_vtable!((), |f, _opts| write!(f, "()")) };
44
45    const SHAPE: &'static Shape = &const {
46        Shape::builder_for_sized::<Self>()
47            .type_identifier("()")
48            .ty(Type::User(UserType::Struct(StructType {
49                repr: Repr::default(),
50                kind: StructKind::Tuple,
51                fields: &[],
52            })))
53            .build()
54    };
55}
56
57unsafe impl<'a, T: ?Sized + 'a> Facet<'a> for core::marker::PhantomData<T> {
58    // TODO: we might be able to do something with specialization re: the shape of T?
59    const VTABLE: &'static ValueVTable =
60        &const { value_vtable!((), |f, _opts| write!(f, "{}", Self::SHAPE.type_identifier)) };
61
62    const SHAPE: &'static Shape = &const {
63        Shape::builder_for_sized::<Self>()
64            .type_identifier("PhantomData")
65            .def(Def::Scalar)
66            .ty(Type::User(UserType::Struct(StructType {
67                repr: Repr::default(),
68                kind: StructKind::Unit,
69                fields: &[],
70            })))
71            .build()
72    };
73}
74
75unsafe impl Facet<'_> for char {
76    const VTABLE: &'static ValueVTable = &const {
77        value_vtable!(char, |f, _opts| write!(
78            f,
79            "{}",
80            Self::SHAPE.type_identifier
81        ))
82    };
83
84    const SHAPE: &'static Shape = &const {
85        Shape::builder_for_sized::<Self>()
86            .type_identifier("char")
87            .def(Def::Scalar)
88            .ty(Type::Primitive(PrimitiveType::Textual(TextualType::Char)))
89            .build()
90    };
91}
92
93unsafe impl Facet<'_> for str {
94    const VTABLE: &'static ValueVTable = &const {
95        value_vtable_unsized!(str, |f, _opts| write!(f, "{}", Self::SHAPE.type_identifier))
96    };
97
98    const SHAPE: &'static Shape = &const {
99        Shape::builder_for_unsized::<Self>()
100            .type_identifier("str")
101            .ty(Type::Primitive(PrimitiveType::Textual(TextualType::Str)))
102            .def(Def::Scalar)
103            .build()
104    };
105}
106
107unsafe impl Facet<'_> for bool {
108    const VTABLE: &'static ValueVTable = &const {
109        value_vtable!(bool, |f, _opts| write!(
110            f,
111            "{}",
112            Self::SHAPE.type_identifier
113        ))
114    };
115
116    const SHAPE: &'static Shape = &const {
117        Shape::builder_for_sized::<Self>()
118            .type_identifier("bool")
119            .def(Def::Scalar)
120            .ty(Type::Primitive(PrimitiveType::Boolean))
121            .build()
122    };
123}
124
125macro_rules! impl_facet_for_integer {
126    ($type:ty) => {
127        unsafe impl<'a> Facet<'a> for $type {
128            const VTABLE: &'static ValueVTable = &const {
129                value_vtable!($type, |f, _opts| write!(
130                    f,
131                    "{}",
132                    Self::SHAPE.type_identifier
133                ))
134            };
135
136            const SHAPE: &'static Shape = &const {
137                Shape::builder_for_sized::<Self>()
138                    .type_identifier(stringify!($type))
139                    .ty(Type::Primitive(PrimitiveType::Numeric(
140                        NumericType::Integer {
141                            signed: (1 as $type).checked_neg().is_some(),
142                        },
143                    )))
144                    .def(Def::Scalar)
145                    .build()
146            };
147        }
148
149        unsafe impl<'a> Facet<'a> for NonZero<$type> {
150            const VTABLE: &'static ValueVTable = &const {
151                // Define conversion functions for transparency
152                unsafe fn try_from<'dst>(
153                    src_ptr: PtrConst<'_>,
154                    src_shape: &'static Shape,
155                    dst: PtrUninit<'dst>,
156                ) -> Result<PtrMut<'dst>, TryFromError> {
157                    if src_shape == <$type as Facet>::SHAPE {
158                        // Get the inner value and check that it's non-zero
159                        let value = unsafe { *src_ptr.get::<$type>() };
160                        let nz = NonZero::new(value)
161                            .ok_or_else(|| TryFromError::Generic("value should be non-zero"))?;
162
163                        // Put the NonZero value into the destination
164                        Ok(unsafe { dst.put(nz) })
165                    } else {
166                        let inner_try_from =
167                            (<$type as Facet>::SHAPE.vtable.sized().unwrap().try_from)().ok_or(
168                                TryFromError::UnsupportedSourceShape {
169                                    src_shape,
170                                    expected: &[<$type as Facet>::SHAPE],
171                                },
172                            )?;
173
174                        // fallback to inner's try_from
175                        // This relies on the fact that `dst` is the same size as `NonZero<$type>`
176                        // which should be true because `NonZero` is `repr(transparent)`
177                        let inner_result = unsafe { (inner_try_from)(src_ptr, src_shape, dst) };
178                        match inner_result {
179                            Ok(result) => {
180                                // After conversion to inner type, wrap as NonZero
181                                let value = unsafe { *result.get::<$type>() };
182                                let nz = NonZero::new(value).ok_or_else(|| {
183                                    TryFromError::Generic("value should be non-zero")
184                                })?;
185                                Ok(unsafe { dst.put(nz) })
186                            }
187                            Err(e) => Err(e),
188                        }
189                    }
190                }
191
192                unsafe fn try_into_inner<'dst>(
193                    src_ptr: PtrMut<'_>,
194                    dst: PtrUninit<'dst>,
195                ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
196                    // Get the NonZero value and extract the inner value
197                    let nz = unsafe { *src_ptr.get::<NonZero<$type>>() };
198                    // Put the inner value into the destination
199                    Ok(unsafe { dst.put(nz.get()) })
200                }
201
202                unsafe fn try_borrow_inner(
203                    src_ptr: PtrConst<'_>,
204                ) -> Result<PtrConst<'_>, TryBorrowInnerError> {
205                    // NonZero<T> has the same memory layout as T, so we can return the input pointer directly
206                    Ok(src_ptr)
207                }
208
209                let mut vtable = value_vtable!($type, |f, _opts| write!(
210                    f,
211                    "{}<{}>",
212                    Self::SHAPE.type_identifier,
213                    stringify!($type)
214                ));
215
216                // Add our new transparency functions
217                {
218                    let vtable_sized = vtable.sized_mut().unwrap();
219                    vtable_sized.try_from = || Some(try_from);
220                    vtable_sized.try_into_inner = || Some(try_into_inner);
221                    vtable_sized.try_borrow_inner = || Some(try_borrow_inner);
222                }
223
224                vtable
225            };
226
227            const SHAPE: &'static Shape = &const {
228                // Function to return inner type's shape
229                fn inner_shape() -> &'static Shape {
230                    <$type as Facet>::SHAPE
231                }
232
233                Shape::builder_for_sized::<Self>()
234                    .type_identifier("NonZero")
235                    .def(Def::Scalar)
236                    .ty(Type::User(UserType::Struct(StructType {
237                        repr: Repr::transparent(),
238                        kind: StructKind::TupleStruct,
239                        fields: &const {
240                            [Field::builder()
241                                .name("0")
242                                // TODO: is it correct to represent $type here, when we, in
243                                // fact, store $type::NonZeroInner.
244                                .shape(<$type>::SHAPE)
245                                .offset(0)
246                                .flags(FieldFlags::EMPTY)
247                                .build()]
248                        },
249                    })))
250                    .inner(inner_shape)
251                    .build()
252            };
253        }
254    };
255}
256
257impl_facet_for_integer!(u8);
258impl_facet_for_integer!(i8);
259impl_facet_for_integer!(u16);
260impl_facet_for_integer!(i16);
261impl_facet_for_integer!(u32);
262impl_facet_for_integer!(i32);
263impl_facet_for_integer!(u64);
264impl_facet_for_integer!(i64);
265impl_facet_for_integer!(u128);
266impl_facet_for_integer!(i128);
267impl_facet_for_integer!(usize);
268impl_facet_for_integer!(isize);
269
270unsafe impl Facet<'_> for f32 {
271    const VTABLE: &'static ValueVTable =
272        &const { value_vtable!(f32, |f, _opts| write!(f, "{}", Self::SHAPE.type_identifier)) };
273
274    const SHAPE: &'static Shape = &const {
275        Shape::builder_for_sized::<Self>()
276            .type_identifier("f32")
277            .ty(Type::Primitive(PrimitiveType::Numeric(NumericType::Float)))
278            .def(Def::Scalar)
279            .build()
280    };
281}
282
283unsafe impl Facet<'_> for f64 {
284    const VTABLE: &'static ValueVTable = &const {
285        let mut vtable =
286            value_vtable!(f64, |f, _opts| write!(f, "{}", Self::SHAPE.type_identifier));
287
288        {
289            let vtable_sized = vtable.sized_mut().unwrap();
290            vtable_sized.try_from = || {
291                Some(|source, source_shape, dest| {
292                    if source_shape == Self::SHAPE {
293                        return Ok(unsafe { dest.copy_from(source, source_shape)? });
294                    }
295                    if source_shape == u64::SHAPE {
296                        let value: u64 = *unsafe { source.get::<u64>() };
297                        let converted: f64 = value as f64;
298                        return Ok(unsafe { dest.put::<f64>(converted) });
299                    }
300                    if source_shape == i64::SHAPE {
301                        let value: i64 = *unsafe { source.get::<i64>() };
302                        let converted: f64 = value as f64;
303                        return Ok(unsafe { dest.put::<f64>(converted) });
304                    }
305                    if source_shape == f32::SHAPE {
306                        let value: f32 = *unsafe { source.get::<f32>() };
307                        let converted: f64 = value as f64;
308                        return Ok(unsafe { dest.put::<f64>(converted) });
309                    }
310                    Err(TryFromError::UnsupportedSourceShape {
311                        src_shape: source_shape,
312                        expected: &[Self::SHAPE, u64::SHAPE, i64::SHAPE, f32::SHAPE],
313                    })
314                })
315            };
316        }
317
318        vtable
319    };
320
321    const SHAPE: &'static Shape = &const {
322        Shape::builder_for_sized::<Self>()
323            .type_identifier("f64")
324            .ty(Type::Primitive(PrimitiveType::Numeric(NumericType::Float)))
325            .def(Def::Scalar)
326            .build()
327    };
328}
329
330unsafe impl Facet<'_> for core::net::SocketAddr {
331    const VTABLE: &'static ValueVTable = &const {
332        value_vtable!(core::net::SocketAddr, |f, _opts| write!(
333            f,
334            "{}",
335            Self::SHAPE.type_identifier
336        ))
337    };
338
339    const SHAPE: &'static Shape = &const {
340        Shape::builder_for_sized::<Self>()
341            .type_identifier("SocketAddr")
342            .ty(Type::User(UserType::Opaque))
343            .def(Def::Scalar)
344            .build()
345    };
346}
347
348unsafe impl Facet<'_> for core::net::IpAddr {
349    const VTABLE: &'static ValueVTable = &const {
350        value_vtable!(core::net::IpAddr, |f, _opts| write!(
351            f,
352            "{}",
353            Self::SHAPE.type_identifier
354        ))
355    };
356
357    const SHAPE: &'static Shape = &const {
358        Shape::builder_for_sized::<Self>()
359            .type_identifier("IpAddr")
360            .ty(Type::User(UserType::Opaque))
361            .def(Def::Scalar)
362            .build()
363    };
364}
365
366unsafe impl Facet<'_> for core::net::Ipv4Addr {
367    const VTABLE: &'static ValueVTable = &const {
368        value_vtable!(core::net::Ipv4Addr, |f, _opts| write!(
369            f,
370            "{}",
371            Self::SHAPE.type_identifier
372        ))
373    };
374
375    const SHAPE: &'static Shape = &const {
376        Shape::builder_for_sized::<Self>()
377            .type_identifier("Ipv4Addr")
378            .ty(Type::User(UserType::Opaque))
379            .def(Def::Scalar)
380            .build()
381    };
382}
383
384unsafe impl Facet<'_> for core::net::Ipv6Addr {
385    const VTABLE: &'static ValueVTable = &const {
386        value_vtable!(core::net::Ipv6Addr, |f, _opts| write!(
387            f,
388            "{}",
389            Self::SHAPE.type_identifier
390        ))
391    };
392
393    const SHAPE: &'static Shape = &const {
394        Shape::builder_for_sized::<Self>()
395            .type_identifier("Ipv6Addr")
396            .ty(Type::User(UserType::Opaque))
397            .def(Def::Scalar)
398            .build()
399    };
400}