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