1use crate::{
14 value::{ExternAddr, FuncAddr, Ref, F32, F64},
15 NumType, RefType, ValType, Value,
16};
17
18use alloc::{fmt::Debug, vec, vec::Vec};
19
20pub trait InteropValue
23where
24 Self: Copy + Debug + PartialEq + TryFrom<Value, Error = ()>,
25 Value: From<Self>,
26{
27 const TY: ValType;
28}
29
30impl InteropValue for u32 {
31 const TY: ValType = ValType::NumType(NumType::I32);
32}
33
34impl InteropValue for i32 {
35 const TY: ValType = ValType::NumType(NumType::I32);
36}
37
38impl InteropValue for u64 {
39 const TY: ValType = ValType::NumType(NumType::I64);
40}
41
42impl InteropValue for i64 {
43 const TY: ValType = ValType::NumType(NumType::I64);
44}
45
46impl InteropValue for f32 {
47 const TY: ValType = ValType::NumType(NumType::F32);
48}
49
50impl InteropValue for f64 {
51 const TY: ValType = ValType::NumType(NumType::F64);
52}
53
54impl InteropValue for [u8; 16] {
55 const TY: ValType = ValType::VecType;
56}
57
58impl InteropValue for RefFunc {
59 const TY: ValType = ValType::RefType(RefType::FuncRef);
60}
61
62impl InteropValue for RefExtern {
63 const TY: ValType = ValType::RefType(RefType::ExternRef);
64}
65
66impl From<f32> for Value {
67 fn from(value: f32) -> Self {
68 F32(value).into()
69 }
70}
71
72impl TryFrom<Value> for f32 {
73 type Error = ();
74
75 fn try_from(value: Value) -> Result<Self, Self::Error> {
76 F32::try_from(value).map(|f| f.0)
77 }
78}
79
80impl From<f64> for Value {
81 fn from(value: f64) -> Self {
82 F64(value).into()
83 }
84}
85
86impl TryFrom<Value> for f64 {
87 type Error = ();
88
89 fn try_from(value: Value) -> Result<Self, Self::Error> {
90 F64::try_from(value).map(|f| f.0)
91 }
92}
93
94#[derive(Debug, Copy, Clone, PartialEq)]
95pub struct RefFunc(pub Option<FuncAddr>);
96
97impl From<RefFunc> for Value {
98 fn from(value: RefFunc) -> Self {
99 match value.0 {
100 Some(func_addr) => Ref::Func(func_addr),
101 None => Ref::Null(RefType::FuncRef),
102 }
103 .into()
104 }
105}
106
107impl TryFrom<Value> for RefFunc {
108 type Error = ();
109
110 fn try_from(value: Value) -> Result<Self, Self::Error> {
111 match Ref::try_from(value)? {
112 Ref::Func(func_addr) => Ok(Self(Some(func_addr))),
113 Ref::Null(RefType::FuncRef) => Ok(Self(None)),
114 _ => Err(()),
115 }
116 }
117}
118
119#[derive(Debug, Copy, Clone, PartialEq)]
120pub struct RefExtern(pub Option<ExternAddr>);
121
122impl From<RefExtern> for Value {
123 fn from(value: RefExtern) -> Self {
124 match value.0 {
125 Some(extern_addr) => Ref::Extern(extern_addr),
126 None => Ref::Null(RefType::ExternRef),
127 }
128 .into()
129 }
130}
131
132impl TryFrom<Value> for RefExtern {
133 type Error = ();
134
135 fn try_from(value: Value) -> Result<Self, Self::Error> {
136 match Ref::try_from(value)? {
137 Ref::Extern(extern_addr) => Ok(Self(Some(extern_addr))),
138 Ref::Null(RefType::ExternRef) => Ok(Self(None)),
139 _ => Err(()),
140 }
141 }
142}
143
144pub trait InteropValueList: Debug + Copy {
146 const TYS: &'static [ValType];
147
148 fn into_values(self) -> Vec<Value>;
149
150 fn try_from_values(values: impl ExactSizeIterator<Item = Value>) -> Result<Self, ()>;
151}
152
153impl InteropValueList for () {
154 const TYS: &'static [ValType] = &[];
155
156 fn into_values(self) -> Vec<Value> {
157 Vec::new()
158 }
159
160 fn try_from_values(values: impl ExactSizeIterator<Item = Value>) -> Result<Self, ()> {
161 if values.len() != 0 {
162 return Err(());
163 }
164
165 Ok(())
166 }
167}
168
169impl<A> InteropValueList for A
170where
171 A: InteropValue,
172 Value: From<A>,
173{
174 const TYS: &'static [ValType] = &[A::TY];
175
176 fn into_values(self) -> Vec<Value> {
177 vec![self.into()]
178 }
179
180 fn try_from_values(mut values: impl ExactSizeIterator<Item = Value>) -> Result<Self, ()> {
181 if values.len() != Self::TYS.len() {
182 return Err(());
183 }
184
185 A::try_from(values.next().unwrap())
186 }
187}
188
189impl<A> InteropValueList for (A,)
190where
191 A: InteropValue,
192 Value: From<A>,
193{
194 const TYS: &'static [ValType] = &[A::TY];
195
196 fn into_values(self) -> Vec<Value> {
197 vec![self.0.into()]
198 }
199
200 fn try_from_values(mut values: impl ExactSizeIterator<Item = Value>) -> Result<Self, ()> {
201 if values.len() != Self::TYS.len() {
202 return Err(());
203 }
204
205 Ok((A::try_from(values.next().unwrap())?,))
206 }
207}
208
209impl<A, B> InteropValueList for (A, B)
210where
211 A: InteropValue,
212 B: InteropValue,
213 Value: From<A> + From<B>,
214{
215 const TYS: &'static [ValType] = &[A::TY, B::TY];
216
217 fn into_values(self) -> Vec<Value> {
218 vec![self.0.into(), self.1.into()]
219 }
220
221 fn try_from_values(mut values: impl ExactSizeIterator<Item = Value>) -> Result<Self, ()> {
222 if values.len() != Self::TYS.len() {
223 return Err(());
224 }
225
226 Ok((
227 A::try_from(values.next().unwrap())?,
228 B::try_from(values.next().unwrap())?,
229 ))
230 }
231}
232
233impl<A, B, C> InteropValueList for (A, B, C)
234where
235 A: InteropValue,
236 B: InteropValue,
237 C: InteropValue,
238 Value: From<A> + From<B> + From<C>,
239{
240 const TYS: &'static [ValType] = &[A::TY, B::TY, C::TY];
241
242 fn into_values(self) -> Vec<Value> {
243 vec![self.0.into(), self.1.into(), self.2.into()]
244 }
245
246 fn try_from_values(mut values: impl ExactSizeIterator<Item = Value>) -> Result<Self, ()> {
247 if values.len() != Self::TYS.len() {
248 return Err(());
249 }
250
251 Ok((
252 A::try_from(values.next().unwrap())?,
253 B::try_from(values.next().unwrap())?,
254 C::try_from(values.next().unwrap())?,
255 ))
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use crate::value::{ExternAddr, FuncAddr, Value};
262 use alloc::vec::Vec;
263
264 use super::{InteropValueList, RefExtern, RefFunc};
265
266 #[test]
267 fn roundtrip_single_u32() {
268 const RUST_VALUE: u32 = 5;
269 let wasm_value: Value = RUST_VALUE.into();
270 assert_eq!(wasm_value.try_into(), Ok::<u32, ()>(RUST_VALUE));
271 assert_eq!(wasm_value.try_into(), Ok::<i32, ()>(RUST_VALUE as i32));
272 assert_eq!(wasm_value.try_into(), Err::<u64, ()>(()));
273 assert_eq!(wasm_value.try_into(), Err::<i64, ()>(()));
274 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
275 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
276 assert_eq!(wasm_value.try_into(), Err::<RefFunc, ()>(()));
277 assert_eq!(wasm_value.try_into(), Err::<RefExtern, ()>(()));
278 }
279
280 #[test]
281 fn roundtrip_single_i32() {
282 const RUST_VALUE: i32 = 5;
283 let wasm_value: Value = RUST_VALUE.into();
284 assert_eq!(wasm_value.try_into(), Ok::<u32, ()>(RUST_VALUE as u32));
285 assert_eq!(wasm_value.try_into(), Ok::<i32, ()>(RUST_VALUE));
286 assert_eq!(wasm_value.try_into(), Err::<u64, ()>(()));
287 assert_eq!(wasm_value.try_into(), Err::<i64, ()>(()));
288 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
289 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
290 assert_eq!(wasm_value.try_into(), Err::<RefFunc, ()>(()));
291 assert_eq!(wasm_value.try_into(), Err::<RefExtern, ()>(()));
292 }
293
294 #[test]
295 fn roundtrip_single_u64() {
296 const RUST_VALUE: u64 = 5;
297 let wasm_value: Value = RUST_VALUE.into();
298 assert_eq!(wasm_value.try_into(), Err::<u32, ()>(()));
299 assert_eq!(wasm_value.try_into(), Err::<i32, ()>(()));
300 assert_eq!(wasm_value.try_into(), Ok::<u64, ()>(RUST_VALUE));
301 assert_eq!(wasm_value.try_into(), Ok::<i64, ()>(RUST_VALUE as i64));
302 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
303 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
304 assert_eq!(wasm_value.try_into(), Err::<RefFunc, ()>(()));
305 assert_eq!(wasm_value.try_into(), Err::<RefExtern, ()>(()));
306 }
307
308 #[test]
309 fn roundtrip_single_i64() {
310 const RUST_VALUE: i64 = 5;
311 let wasm_value: Value = RUST_VALUE.into();
312 assert_eq!(wasm_value.try_into(), Err::<u32, ()>(()));
313 assert_eq!(wasm_value.try_into(), Err::<i32, ()>(()));
314 assert_eq!(wasm_value.try_into(), Ok::<u64, ()>(RUST_VALUE as u64));
315 assert_eq!(wasm_value.try_into(), Ok::<i64, ()>(RUST_VALUE));
316 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
317 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
318 assert_eq!(wasm_value.try_into(), Err::<RefFunc, ()>(()));
319 assert_eq!(wasm_value.try_into(), Err::<RefExtern, ()>(()));
320 }
321
322 #[test]
323 fn roundtrip_single_f32() {
324 const RUST_VALUE: f32 = 123.12;
325 let wasm_value: Value = RUST_VALUE.into();
326 assert_eq!(wasm_value.try_into(), Err::<u32, ()>(()));
327 assert_eq!(wasm_value.try_into(), Err::<i32, ()>(()));
328 assert_eq!(wasm_value.try_into(), Err::<u64, ()>(()));
329 assert_eq!(wasm_value.try_into(), Err::<i64, ()>(()));
330 assert_eq!(wasm_value.try_into(), Ok::<f32, ()>(RUST_VALUE));
331 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
332 assert_eq!(wasm_value.try_into(), Err::<RefFunc, ()>(()));
333 assert_eq!(wasm_value.try_into(), Err::<RefExtern, ()>(()));
334 }
335
336 #[test]
337 fn roundtrip_single_f64() {
338 const RUST_VALUE: f64 = 123.12;
339 let wasm_value: Value = RUST_VALUE.into();
340 assert_eq!(wasm_value.try_into(), Err::<u32, ()>(()));
341 assert_eq!(wasm_value.try_into(), Err::<i32, ()>(()));
342 assert_eq!(wasm_value.try_into(), Err::<u64, ()>(()));
343 assert_eq!(wasm_value.try_into(), Err::<i64, ()>(()));
344 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
345 assert_eq!(wasm_value.try_into(), Ok::<f64, ()>(RUST_VALUE));
346 assert_eq!(wasm_value.try_into(), Err::<RefFunc, ()>(()));
347 assert_eq!(wasm_value.try_into(), Err::<RefExtern, ()>(()));
348 }
349
350 #[test]
351 fn roundtrip_single_ref_func() {
352 const RUST_VALUE: RefFunc = RefFunc(Some(FuncAddr(57)));
353 let wasm_value: Value = RUST_VALUE.into();
354 assert_eq!(wasm_value.try_into(), Err::<u32, ()>(()));
355 assert_eq!(wasm_value.try_into(), Err::<i32, ()>(()));
356 assert_eq!(wasm_value.try_into(), Err::<u64, ()>(()));
357 assert_eq!(wasm_value.try_into(), Err::<i64, ()>(()));
358 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
359 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
360 assert_eq!(wasm_value.try_into(), Ok::<RefFunc, ()>(RUST_VALUE));
361 assert_eq!(wasm_value.try_into(), Err::<RefExtern, ()>(()));
362 }
363
364 #[test]
365 fn roundtrip_single_ref_extern() {
366 const RUST_VALUE: RefExtern = RefExtern(Some(ExternAddr(51)));
367 let wasm_value: Value = RUST_VALUE.into();
368 assert_eq!(wasm_value.try_into(), Err::<u32, ()>(()));
369 assert_eq!(wasm_value.try_into(), Err::<i32, ()>(()));
370 assert_eq!(wasm_value.try_into(), Err::<u64, ()>(()));
371 assert_eq!(wasm_value.try_into(), Err::<i64, ()>(()));
372 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
373 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
374 assert_eq!(wasm_value.try_into(), Err::<RefFunc, ()>(()));
375 assert_eq!(wasm_value.try_into(), Ok::<RefExtern, ()>(RUST_VALUE));
376 }
377
378 #[test]
379 fn roundtrip_single_ref_func_null() {
380 const RUST_VALUE: RefFunc = RefFunc(None);
381 let wasm_value: Value = RUST_VALUE.into();
382 assert_eq!(wasm_value.try_into(), Err::<u32, ()>(()));
383 assert_eq!(wasm_value.try_into(), Err::<i32, ()>(()));
384 assert_eq!(wasm_value.try_into(), Err::<u64, ()>(()));
385 assert_eq!(wasm_value.try_into(), Err::<i64, ()>(()));
386 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
387 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
388 assert_eq!(wasm_value.try_into(), Ok::<RefFunc, ()>(RUST_VALUE));
389 assert_eq!(wasm_value.try_into(), Err::<RefExtern, ()>(()));
390 }
391
392 #[test]
393 fn roundtrip_single_ref_extern_null() {
394 const RUST_VALUE: RefExtern = RefExtern(None);
395 let wasm_value: Value = RUST_VALUE.into();
396 assert_eq!(wasm_value.try_into(), Err::<u32, ()>(()));
397 assert_eq!(wasm_value.try_into(), Err::<i32, ()>(()));
398 assert_eq!(wasm_value.try_into(), Err::<u64, ()>(()));
399 assert_eq!(wasm_value.try_into(), Err::<i64, ()>(()));
400 assert_eq!(wasm_value.try_into(), Err::<f32, ()>(()));
401 assert_eq!(wasm_value.try_into(), Err::<f64, ()>(()));
402 assert_eq!(wasm_value.try_into(), Err::<RefFunc, ()>(()));
403 assert_eq!(wasm_value.try_into(), Ok::<RefExtern, ()>(RUST_VALUE));
404 }
405
406 #[test]
407 fn roundtrip_list0() {
408 const RUST_VALUES: () = ();
409 let wasm_values: Vec<Value> = RUST_VALUES.into_values();
410 let roundtrip_rust_values = InteropValueList::try_from_values(wasm_values.into_iter());
411 assert_eq!(roundtrip_rust_values, Ok(RUST_VALUES));
412 }
413
414 #[test]
415 fn roundtrip_list1_single() {
416 const RUST_VALUES: u32 = 5;
417 let wasm_values: Vec<Value> = RUST_VALUES.into_values();
418 let roundtrip_rust_values = InteropValueList::try_from_values(wasm_values.into_iter());
419 assert_eq!(roundtrip_rust_values, Ok(RUST_VALUES));
420 }
421
422 #[test]
423 fn roundtrip_list1() {
424 const RUST_VALUES: (u32,) = (5,);
425 let wasm_values: Vec<Value> = RUST_VALUES.into_values();
426 let roundtrip_rust_values = InteropValueList::try_from_values(wasm_values.into_iter());
427 assert_eq!(roundtrip_rust_values, Ok(RUST_VALUES));
428 }
429
430 #[test]
431 fn roundtrip_list2() {
432 const RUST_VALUES: (f32, RefFunc) = (3.0, RefFunc(Some(FuncAddr(7))));
433 let wasm_values: Vec<Value> = RUST_VALUES.into_values();
434 let roundtrip_rust_values = InteropValueList::try_from_values(wasm_values.into_iter());
435 assert_eq!(roundtrip_rust_values, Ok(RUST_VALUES));
436 }
437
438 #[test]
439 fn roundtrip_list3() {
440 const RUST_VALUES: (RefExtern, u64, i32) =
441 (RefExtern(Some(ExternAddr(123))), 8472846, -61864);
442 let wasm_values: Vec<Value> = RUST_VALUES.into_values();
443 let roundtrip_rust_values = InteropValueList::try_from_values(wasm_values.into_iter());
444 assert_eq!(roundtrip_rust_values, Ok(RUST_VALUES))
445 }
446
447 #[test]
448 fn list_incorrect_lengths() {
449 let wasm_values0: Vec<Value> = ().into_values();
450 let wasm_values1_single: Vec<Value> = 5u32.into_values();
451 let wasm_values1: Vec<Value> = (5u32,).into_values();
452 let wasm_values2: Vec<Value> = (5u32, 5u32).into_values();
453 let wasm_values3: Vec<Value> = (5u32, 5u32, 5u32).into_values();
454
455 assert_eq!(
456 InteropValueList::try_from_values(wasm_values0.clone().into_iter()),
457 Err::<u32, ()>(())
458 );
459 assert_eq!(
460 InteropValueList::try_from_values(wasm_values0.clone().into_iter()),
461 Err::<(u32,), ()>(())
462 );
463 assert_eq!(
464 InteropValueList::try_from_values(wasm_values0.clone().into_iter()),
465 Err::<(u32, u32), ()>(())
466 );
467 assert_eq!(
468 InteropValueList::try_from_values(wasm_values0.clone().into_iter()),
469 Err::<(u32, u32, u32), ()>(())
470 );
471
472 assert_eq!(
473 InteropValueList::try_from_values(wasm_values1_single.clone().into_iter()),
474 Err::<(), ()>(())
475 );
476 assert_eq!(
477 InteropValueList::try_from_values(wasm_values1_single.clone().into_iter()),
478 Err::<(u32, u32), ()>(())
479 );
480 assert_eq!(
481 InteropValueList::try_from_values(wasm_values1_single.clone().into_iter()),
482 Err::<(u32, u32, u32), ()>(())
483 );
484
485 assert_eq!(
486 InteropValueList::try_from_values(wasm_values1.clone().into_iter()),
487 Err::<(), ()>(())
488 );
489 assert_eq!(
490 InteropValueList::try_from_values(wasm_values1.clone().into_iter()),
491 Err::<(u32, u32), ()>(())
492 );
493 assert_eq!(
494 InteropValueList::try_from_values(wasm_values1.clone().into_iter()),
495 Err::<(u32, u32, u32), ()>(())
496 );
497
498 assert_eq!(
499 InteropValueList::try_from_values(wasm_values2.clone().into_iter()),
500 Err::<(), ()>(())
501 );
502 assert_eq!(
503 InteropValueList::try_from_values(wasm_values2.clone().into_iter()),
504 Err::<(u32,), ()>(())
505 );
506 assert_eq!(
507 InteropValueList::try_from_values(wasm_values2.clone().into_iter()),
508 Err::<(u32, u32, u32), ()>(())
509 );
510
511 assert_eq!(
512 InteropValueList::try_from_values(wasm_values3.clone().into_iter()),
513 Err::<(), ()>(())
514 );
515 assert_eq!(
516 InteropValueList::try_from_values(wasm_values3.clone().into_iter()),
517 Err::<(u32,), ()>(())
518 );
519 assert_eq!(
520 InteropValueList::try_from_values(wasm_values3.clone().into_iter()),
521 Err::<(u32, u32), ()>(())
522 );
523 }
524}