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