1extern crate alloc;
8
9use crate::{
10 Def, Facet, NumericType, PrimitiveType, PtrConst, Shape, ShapeBuilder, TryFromOutcome, Type,
11 TypeOpsDirect, VTableDirect, type_ops_direct, vtable_direct,
12};
13
14macro_rules! integer_try_from {
16 ($target:ty) => {{
17 unsafe fn try_from_any(
20 dst: *mut $target,
21 src_shape: &'static Shape,
22 src: PtrConst,
23 ) -> TryFromOutcome {
24 use core::convert::TryInto;
25
26 macro_rules! convert {
29 ($src_ty:ty) => {{
30 let src_val = unsafe { *(src.as_byte_ptr() as *const $src_ty) };
31 <$src_ty as TryInto<$target>>::try_into(src_val).map_err(|_| {
32 alloc::format!(
33 "conversion from {} to {} failed: value {} out of range",
34 src_shape.type_identifier,
35 stringify!($target),
36 src_val
37 )
38 })
39 }};
40 }
41
42 let result: Result<$target, alloc::string::String> = match src_shape.type_identifier {
44 "i8" => convert!(i8),
45 "i16" => convert!(i16),
46 "i32" => convert!(i32),
47 "i64" => convert!(i64),
48 "i128" => convert!(i128),
49 "isize" => convert!(isize),
50 "u8" => convert!(u8),
51 "u16" => convert!(u16),
52 "u32" => convert!(u32),
53 "u64" => convert!(u64),
54 "u128" => convert!(u128),
55 "usize" => convert!(usize),
56 _ => return TryFromOutcome::Unsupported,
57 };
58
59 match result {
60 Ok(value) => {
61 unsafe { dst.write(value) };
62 TryFromOutcome::Converted
63 }
64 Err(e) => TryFromOutcome::Failed(e.into()),
65 }
66 }
67 try_from_any
68 }};
69}
70
71#[inline(always)]
74unsafe fn bool_truthy(value: PtrConst) -> bool {
75 *unsafe { value.get::<bool>() }
76}
77
78macro_rules! define_int_type_ops {
79 ($const_name:ident, $ty:ty, $fn_name:ident) => {
80 #[inline(always)]
81 unsafe fn $fn_name(value: PtrConst) -> bool {
82 *unsafe { value.get::<$ty>() } != 0
83 }
84
85 static $const_name: TypeOpsDirect = TypeOpsDirect {
86 is_truthy: Some($fn_name),
87 ..type_ops_direct!($ty => Default, Clone)
88 };
89 };
90}
91
92macro_rules! define_float_type_ops {
93 ($const_name:ident, $ty:ty, $fn_name:ident) => {
94 #[inline(always)]
95 unsafe fn $fn_name(value: PtrConst) -> bool {
96 let v = *unsafe { value.get::<$ty>() };
97 v != 0.0 && !v.is_nan()
98 }
99
100 static $const_name: TypeOpsDirect = TypeOpsDirect {
101 is_truthy: Some($fn_name),
102 ..type_ops_direct!($ty => Default, Clone)
103 };
104 };
105}
106
107static BOOL_TYPE_OPS: TypeOpsDirect = TypeOpsDirect {
108 is_truthy: Some(bool_truthy),
109 ..type_ops_direct!(bool => Default, Clone)
110};
111
112define_int_type_ops!(U8_TYPE_OPS, u8, u8_truthy);
113define_int_type_ops!(I8_TYPE_OPS, i8, i8_truthy);
114define_int_type_ops!(U16_TYPE_OPS, u16, u16_truthy);
115define_int_type_ops!(I16_TYPE_OPS, i16, i16_truthy);
116define_int_type_ops!(U32_TYPE_OPS, u32, u32_truthy);
117define_int_type_ops!(I32_TYPE_OPS, i32, i32_truthy);
118define_int_type_ops!(U64_TYPE_OPS, u64, u64_truthy);
119define_int_type_ops!(I64_TYPE_OPS, i64, i64_truthy);
120define_int_type_ops!(U128_TYPE_OPS, u128, u128_truthy);
121define_int_type_ops!(I128_TYPE_OPS, i128, i128_truthy);
122define_int_type_ops!(USIZE_TYPE_OPS, usize, usize_truthy);
123define_int_type_ops!(ISIZE_TYPE_OPS, isize, isize_truthy);
124
125define_float_type_ops!(F32_TYPE_OPS, f32, f32_truthy);
126define_float_type_ops!(F64_TYPE_OPS, f64, f64_truthy);
127
128unsafe impl Facet<'_> for bool {
129 const SHAPE: &'static Shape = &const {
130 const VTABLE: VTableDirect = vtable_direct!(bool =>
131 FromStr,
132 Display,
133 Debug,
134 Hash,
135 PartialEq,
136 PartialOrd,
137 Ord,
138 );
139
140 ShapeBuilder::for_sized::<bool>("bool")
141 .ty(Type::Primitive(PrimitiveType::Boolean))
142 .def(Def::Scalar)
143 .vtable_direct(&VTABLE)
144 .type_ops_direct(&BOOL_TYPE_OPS)
145 .eq()
146 .copy()
147 .send()
148 .sync()
149 .build()
150 };
151}
152
153macro_rules! impl_facet_for_integer {
154 ($type:ty, $type_ops:expr) => {
155 unsafe impl<'a> Facet<'a> for $type {
156 const SHAPE: &'static Shape = &const {
157 const VTABLE: VTableDirect = vtable_direct!($type =>
158 FromStr,
159 Display,
160 Debug,
161 Hash,
162 PartialEq,
163 PartialOrd,
164 Ord,
165 [try_from = integer_try_from!($type)],
166 );
167
168 ShapeBuilder::for_sized::<$type>(stringify!($type))
169 .ty(Type::Primitive(PrimitiveType::Numeric(
170 NumericType::Integer {
171 signed: (1 as $type).checked_neg().is_some(),
172 },
173 )))
174 .def(Def::Scalar)
175 .vtable_direct(&VTABLE)
176 .type_ops_direct($type_ops)
177 .eq()
178 .copy()
179 .send()
180 .sync()
181 .build()
182 };
183 }
184 };
185}
186
187impl_facet_for_integer!(u8, &U8_TYPE_OPS);
188impl_facet_for_integer!(i8, &I8_TYPE_OPS);
189impl_facet_for_integer!(u16, &U16_TYPE_OPS);
190impl_facet_for_integer!(i16, &I16_TYPE_OPS);
191impl_facet_for_integer!(u32, &U32_TYPE_OPS);
192impl_facet_for_integer!(i32, &I32_TYPE_OPS);
193impl_facet_for_integer!(u64, &U64_TYPE_OPS);
194impl_facet_for_integer!(i64, &I64_TYPE_OPS);
195impl_facet_for_integer!(u128, &U128_TYPE_OPS);
196impl_facet_for_integer!(i128, &I128_TYPE_OPS);
197impl_facet_for_integer!(usize, &USIZE_TYPE_OPS);
198impl_facet_for_integer!(isize, &ISIZE_TYPE_OPS);
199
200unsafe impl Facet<'_> for f32 {
201 const SHAPE: &'static Shape = &const {
202 const VTABLE: VTableDirect = vtable_direct!(f32 =>
205 FromStr,
206 Display,
207 Debug,
208 PartialEq,
209 PartialOrd,
210 );
211
212 ShapeBuilder::for_sized::<f32>("f32")
213 .ty(Type::Primitive(PrimitiveType::Numeric(NumericType::Float)))
214 .def(Def::Scalar)
215 .vtable_direct(&VTABLE)
216 .type_ops_direct(&F32_TYPE_OPS)
217 .copy()
218 .send()
219 .sync()
220 .build()
221 };
222}
223
224unsafe impl Facet<'_> for f64 {
225 const SHAPE: &'static Shape = &const {
226 const VTABLE: VTableDirect = vtable_direct!(f64 =>
229 FromStr,
230 Display,
231 Debug,
232 PartialEq,
233 PartialOrd,
234 );
235
236 ShapeBuilder::for_sized::<f64>("f64")
237 .ty(Type::Primitive(PrimitiveType::Numeric(NumericType::Float)))
238 .def(Def::Scalar)
239 .vtable_direct(&VTABLE)
240 .type_ops_direct(&F64_TYPE_OPS)
241 .copy()
242 .send()
243 .sync()
244 .build()
245 };
246}
247
248#[cfg(test)]
249mod tests {
250 use crate::{Facet, TypeOps};
251
252 #[test]
253 fn test_scalar_shapes() {
254 assert!(bool::SHAPE.vtable.has_debug());
255 assert!(bool::SHAPE.vtable.has_display());
256 assert!(
258 matches!(bool::SHAPE.type_ops, Some(TypeOps::Direct(ops)) if ops.default_in_place.is_some())
259 );
260
261 assert!(u32::SHAPE.vtable.has_debug());
262 assert!(u32::SHAPE.vtable.has_display());
263 assert!(u32::SHAPE.vtable.has_hash());
264
265 assert!(f64::SHAPE.vtable.has_debug());
266 assert!(f64::SHAPE.vtable.has_display());
267 assert!(!f64::SHAPE.vtable.has_hash()); }
269}