1#[cfg(feature = "simd")]
2use crate::V128;
3use crate::{F32, F64};
4use core::{
5 error::Error,
6 fmt::{self, Display},
7};
8
9#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
13#[cfg_attr(not(feature = "simd"), repr(transparent))]
14#[cfg_attr(feature = "simd", repr(C))]
15pub struct UntypedVal {
16 pub(crate) lo64: u64,
22 #[cfg(feature = "simd")]
27 pub(crate) hi64: u64,
28}
29
30pub trait ReadAs<T> {
34 fn read_as(&self) -> T;
36}
37
38macro_rules! impl_read_as_for_int {
39 ( $( $int:ty ),* $(,)? ) => {
40 $(
41 impl ReadAs<$int> for UntypedVal {
42 fn read_as(&self) -> $int {
43 self.read_lo64() as $int
44 }
45 }
46 )*
47 };
48}
49impl_read_as_for_int!(i8, i16, i32, i64, u8, u16, u32, u64);
50
51macro_rules! impl_read_as_for_float {
52 ( $( $float:ty ),* $(,)? ) => {
53 $(
54 impl ReadAs<$float> for UntypedVal {
55 fn read_as(&self) -> $float {
56 <$float>::from_bits(self.read_lo64() as _)
57 }
58 }
59 )*
60 };
61}
62impl_read_as_for_float!(f32, f64);
63
64#[cfg(feature = "simd")]
65impl ReadAs<V128> for UntypedVal {
66 fn read_as(&self) -> V128 {
67 V128::from(*self)
69 }
70}
71
72impl ReadAs<bool> for UntypedVal {
73 fn read_as(&self) -> bool {
74 self.read_lo64() != 0
75 }
76}
77
78pub trait WriteAs<T> {
82 fn write_as(&mut self, value: T);
84}
85
86macro_rules! impl_write_as_for_int {
87 ( $( $int:ty as $as:ty ),* $(,)? ) => {
88 $(
89 impl WriteAs<$int> for UntypedVal {
90 #[allow(clippy::cast_lossless)]
91 fn write_as(&mut self, value: $int) {
92 self.write_lo64(value as $as as _)
93 }
94 }
95
96 impl WriteAs<::core::num::NonZero<$int>> for UntypedVal {
97 fn write_as(&mut self, value: ::core::num::NonZero<$int>) {
98 <UntypedVal as WriteAs<$int>>::write_as(self, value.get())
99 }
100 }
101 )*
102 };
103}
104impl_write_as_for_int!(i8 as u8, i16 as u16, i32 as u32, i64 as u64);
105
106macro_rules! impl_write_as_for_uint {
107 ( $( $int:ty ),* $(,)? ) => {
108 $(
109 impl WriteAs<$int> for UntypedVal {
110 #[allow(clippy::cast_lossless)]
111 fn write_as(&mut self, value: $int) {
112 self.write_lo64(value as _)
113 }
114 }
115
116 impl WriteAs<::core::num::NonZero<$int>> for UntypedVal {
117 fn write_as(&mut self, value: ::core::num::NonZero<$int>) {
118 <UntypedVal as WriteAs<$int>>::write_as(self, value.get())
119 }
120 }
121 )*
122 };
123}
124impl_write_as_for_uint!(u8, u16, u32, u64);
125
126impl WriteAs<bool> for UntypedVal {
127 #[allow(clippy::cast_lossless)]
128 fn write_as(&mut self, value: bool) {
129 self.write_lo64(value as _)
130 }
131}
132
133macro_rules! impl_write_as_for_float {
134 ( $( $float:ty ),* $(,)? ) => {
135 $(
136 impl WriteAs<$float> for UntypedVal {
137 #[allow(clippy::cast_lossless)]
138 fn write_as(&mut self, value: $float) {
139 self.write_lo64(<$float>::to_bits(value) as _)
140 }
141 }
142 )*
143 };
144}
145impl_write_as_for_float!(f32, f64);
146
147#[cfg(feature = "simd")]
148impl WriteAs<V128> for UntypedVal {
149 fn write_as(&mut self, value: V128) {
150 *self = UntypedVal::from(value);
152 }
153}
154
155impl UntypedVal {
156 fn read_lo64(&self) -> u64 {
160 self.lo64
161 }
162
163 fn write_lo64(&mut self, bits: u64) {
165 self.lo64 = bits;
166 }
167
168 pub const fn from_bits64(lo64: u64) -> Self {
172 Self {
173 lo64,
174 #[cfg(feature = "simd")]
175 hi64: 0,
176 }
177 }
178
179 pub const fn to_bits64(self) -> u64 {
183 self.lo64
184 }
185}
186
187macro_rules! impl_from_untyped_for_int {
188 ( $( $int:ty ),* $(,)? ) => {
189 $(
190 impl From<UntypedVal> for $int {
191 fn from(untyped: UntypedVal) -> Self {
192 untyped.to_bits64() as _
193 }
194 }
195 )*
196 };
197}
198impl_from_untyped_for_int!(i8, i16, i32, i64, u8, u16, u32, u64);
199
200macro_rules! impl_from_untyped_for_float {
201 ( $( $float:ty ),* $(,)? ) => {
202 $(
203 impl From<UntypedVal> for $float {
204 fn from(untyped: UntypedVal) -> Self {
205 Self::from_bits(untyped.to_bits64() as _)
206 }
207 }
208 )*
209 };
210}
211impl_from_untyped_for_float!(f32, f64, F32, F64);
212
213#[cfg(feature = "simd")]
214impl From<UntypedVal> for V128 {
215 fn from(value: UntypedVal) -> Self {
216 let u128 = (u128::from(value.hi64) << 64) | (u128::from(value.lo64));
217 Self::from(u128)
218 }
219}
220
221#[cfg(feature = "simd")]
222impl From<V128> for UntypedVal {
223 fn from(value: V128) -> Self {
224 let u128 = value.as_u128();
225 let lo64 = u128 as u64;
226 let hi64 = (u128 >> 64) as u64;
227 Self { lo64, hi64 }
228 }
229}
230
231impl From<UntypedVal> for bool {
232 fn from(untyped: UntypedVal) -> Self {
233 untyped.to_bits64() != 0
234 }
235}
236
237macro_rules! impl_from_unsigned_prim {
238 ( $( $prim:ty ),* $(,)? ) => {
239 $(
240 impl From<$prim> for UntypedVal {
241 #[allow(clippy::cast_lossless)]
242 fn from(value: $prim) -> Self {
243 Self::from_bits64(value as _)
244 }
245 }
246
247 impl From<::core::num::NonZero<$prim>> for UntypedVal {
248 fn from(value: ::core::num::NonZero<$prim>) -> Self {
249 <_ as From<$prim>>::from(value.get())
250 }
251 }
252 )*
253 };
254}
255#[rustfmt::skip]
256impl_from_unsigned_prim!(
257 u8, u16, u32, u64,
258);
259
260impl From<bool> for UntypedVal {
261 #[allow(clippy::cast_lossless)]
262 fn from(value: bool) -> Self {
263 Self::from_bits64(value as _)
264 }
265}
266
267macro_rules! impl_from_signed_prim {
268 ( $( $prim:ty as $base:ty ),* $(,)? ) => {
269 $(
270 impl From<$prim> for UntypedVal {
271 #[allow(clippy::cast_lossless)]
272 fn from(value: $prim) -> Self {
273 Self::from_bits64(u64::from(value as $base))
274 }
275 }
276
277 impl From<::core::num::NonZero<$prim>> for UntypedVal {
278 fn from(value: ::core::num::NonZero<$prim>) -> Self {
279 <_ as From<$prim>>::from(value.get())
280 }
281 }
282 )*
283 };
284}
285#[rustfmt::skip]
286impl_from_signed_prim!(
287 i8 as u8,
288 i16 as u16,
289 i32 as u32,
290 i64 as u64,
291);
292
293macro_rules! impl_from_float {
294 ( $( $float:ty ),* $(,)? ) => {
295 $(
296 impl From<$float> for UntypedVal {
297 fn from(value: $float) -> Self {
298 Self::from_bits64(u64::from(value.to_bits()))
299 }
300 }
301 )*
302 };
303}
304impl_from_float!(f32, f64, F32, F64);
305
306macro_rules! for_each_tuple {
308 ($mac:ident) => {
309 $mac!( 0 );
310 $mac!( 1 T1);
311 $mac!( 2 T1 T2);
312 $mac!( 3 T1 T2 T3);
313 $mac!( 4 T1 T2 T3 T4);
314 $mac!( 5 T1 T2 T3 T4 T5);
315 $mac!( 6 T1 T2 T3 T4 T5 T6);
316 $mac!( 7 T1 T2 T3 T4 T5 T6 T7);
317 $mac!( 8 T1 T2 T3 T4 T5 T6 T7 T8);
318 $mac!( 9 T1 T2 T3 T4 T5 T6 T7 T8 T9);
319 $mac!(10 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10);
320 $mac!(11 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11);
321 $mac!(12 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12);
322 $mac!(13 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13);
323 $mac!(14 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14);
324 $mac!(15 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
325 $mac!(16 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16);
326 }
327}
328
329#[derive(Debug, Copy, Clone)]
331pub enum UntypedError {
332 InvalidLen,
334}
335
336impl UntypedError {
337 #[cold]
339 pub fn invalid_len() -> Self {
340 Self::InvalidLen
341 }
342}
343
344impl Error for UntypedError {}
345
346impl Display for UntypedError {
347 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
348 match self {
349 UntypedError::InvalidLen => {
350 write!(f, "mismatched length of the untyped slice",)
351 }
352 }
353 }
354}
355
356impl UntypedVal {
357 pub fn decode_slice<T>(slice: &[Self]) -> Result<T, UntypedError>
368 where
369 T: DecodeUntypedSlice,
370 {
371 <T as DecodeUntypedSlice>::decode_untyped_slice(slice)
372 }
373
374 pub fn encode_slice<T>(slice: &mut [Self], input: T) -> Result<(), UntypedError>
385 where
386 T: EncodeUntypedSlice,
387 {
388 <T as EncodeUntypedSlice>::encode_untyped_slice(input, slice)
389 }
390}
391
392pub trait DecodeUntypedSlice: Sized {
394 fn decode_untyped_slice(params: &[UntypedVal]) -> Result<Self, UntypedError>;
405}
406
407impl<T1> DecodeUntypedSlice for T1
408where
409 T1: From<UntypedVal>,
410{
411 #[inline]
412 fn decode_untyped_slice(results: &[UntypedVal]) -> Result<Self, UntypedError> {
413 <(T1,) as DecodeUntypedSlice>::decode_untyped_slice(results).map(|t| t.0)
414 }
415}
416
417macro_rules! impl_decode_untyped_slice {
418 ( $n:literal $( $tuple:ident )* ) => {
419 impl<$($tuple),*> DecodeUntypedSlice for ($($tuple,)*)
420 where
421 $(
422 $tuple: From<UntypedVal>
423 ),*
424 {
425 #[allow(non_snake_case)]
426 #[inline]
427 fn decode_untyped_slice(results: &[UntypedVal]) -> Result<Self, UntypedError> {
428 match results {
429 &[ $($tuple),* ] => Ok((
430 $(
431 <$tuple as From<UntypedVal>>::from($tuple),
432 )*
433 )),
434 _ => Err(UntypedError::invalid_len()),
435 }
436 }
437 }
438 };
439}
440for_each_tuple!(impl_decode_untyped_slice);
441
442pub trait EncodeUntypedSlice {
444 fn encode_untyped_slice(self, results: &mut [UntypedVal]) -> Result<(), UntypedError>;
455}
456
457impl<T1> EncodeUntypedSlice for T1
458where
459 T1: Into<UntypedVal>,
460{
461 #[inline]
462 fn encode_untyped_slice(self, results: &mut [UntypedVal]) -> Result<(), UntypedError> {
463 <(T1,) as EncodeUntypedSlice>::encode_untyped_slice((self,), results)
464 }
465}
466
467macro_rules! impl_encode_untyped_slice {
468 ( $n:literal $( $tuple:ident )* ) => {
469 impl<$($tuple),*> EncodeUntypedSlice for ($($tuple,)*)
470 where
471 $(
472 $tuple: Into<UntypedVal>
473 ),*
474 {
475 #[allow(non_snake_case)]
476 #[inline]
477 fn encode_untyped_slice<'a>(self, results: &'a mut [UntypedVal]) -> Result<(), UntypedError> {
478 let Ok(_results) = <&'a mut [UntypedVal; $n]>::try_from(results) else {
479 return Err(UntypedError::invalid_len())
480 };
481 let ( $( $tuple ,)* ) = self;
482 let mut _i = 0;
483 $(
484 _results[_i] = <$tuple as Into<UntypedVal>>::into($tuple);
485 _i += 1;
486 )*
487 Ok(())
488 }
489 }
490 };
491}
492for_each_tuple!(impl_encode_untyped_slice);