@@ -152,13 +152,13 @@ impl HostFunction {
152152 /// Create a new typed host function import.
153153 pub fn from < P , R > ( store : & mut Store , func : impl Fn ( FuncContext < ' _ > , P ) -> Result < R > + ' static ) -> Function
154154 where
155- P : FromWasmValueTuple + WasmTypesFromTuple ,
156- R : IntoWasmValueTuple + WasmTypesFromTuple ,
155+ P : FromWasmValues + ToWasmTypes ,
156+ R : IntoWasmValues + ToWasmTypes ,
157157 {
158158 let inner_func = move |ctx : FuncContext < ' _ > , args : & [ WasmValue ] | -> Result < Vec < WasmValue > > {
159- let args = P :: from_wasm_value_tuple ( args) ?;
159+ let args = P :: from_wasm_values ( args) ?;
160160 let result = func ( ctx, args) ?;
161- Ok ( result. into_wasm_value_tuple ( ) )
161+ Ok ( result. into_wasm_values ( ) )
162162 } ;
163163
164164 let ty = Arc :: new ( tinywasm_types:: FuncType :: new ( & P :: wasm_types ( ) , & R :: wasm_types ( ) ) ) ;
@@ -383,47 +383,45 @@ fn collect_call_results(value_stack: &mut ValueStack, func_ty: &FuncType) -> Res
383383 Ok ( res)
384384}
385385
386- pub trait IntoWasmValueTuple {
387- fn into_wasm_value_tuple ( self ) -> Vec < WasmValue > ;
386+ pub trait IntoWasmValues {
387+ fn into_wasm_values ( self ) -> Vec < WasmValue > ;
388388}
389389
390- pub trait FromWasmValueTuple {
391- fn from_wasm_value_tuple ( values : & [ WasmValue ] ) -> Result < Self >
392- where
393- Self : Sized ;
390+ pub trait FromWasmValues : Sized {
391+ fn from_wasm_values ( values : & [ WasmValue ] ) -> Result < Self > ;
394392}
395393
396- impl < P : IntoWasmValueTuple , R : FromWasmValueTuple > FunctionTyped < P , R > {
394+ impl < P : IntoWasmValues , R : FromWasmValues > FunctionTyped < P , R > {
397395 /// Call a typed function
398396 pub fn call ( & self , store : & mut Store , params : P ) -> Result < R > {
399397 // Convert params into Vec<WasmValue>
400- let wasm_values = params. into_wasm_value_tuple ( ) ;
398+ let wasm_values = params. into_wasm_values ( ) ;
401399
402400 // Call the underlying WASM function
403401 let result = self . func . call ( store, & wasm_values) ?;
404402
405403 // Convert the Vec<WasmValue> back to R
406- R :: from_wasm_value_tuple ( & result)
404+ R :: from_wasm_values ( & result)
407405 }
408406
409407 /// Call a typed function and return a resumable execution handle.
410408 ///
411409 /// The handle keeps a mutable borrow of the [`Store`] until completion.
412410 pub fn call_resumable < ' store > ( & self , store : & ' store mut Store , params : P ) -> Result < FuncExecutionTyped < ' store , R > > {
413- let wasm_values = params. into_wasm_value_tuple ( ) ;
411+ let wasm_values = params. into_wasm_values ( ) ;
414412 let execution = self . func . call_resumable ( store, & wasm_values) ?;
415413 Ok ( FuncExecutionTyped { execution, marker : core:: marker:: PhantomData } )
416414 }
417415}
418416
419- impl < ' store , R : FromWasmValueTuple > FuncExecutionTyped < ' store , R > {
417+ impl < ' store , R : FromWasmValues > FuncExecutionTyped < ' store , R > {
420418 /// Resume typed execution with up to `fuel` units of fuel.
421419 ///
422420 /// Fuel is accounted in chunks, so execution may overshoot the requested
423421 /// fuel before returning [`ExecProgress::Suspended`].
424422 pub fn resume_with_fuel ( & mut self , fuel : u32 ) -> Result < ExecProgress < R > > {
425423 match self . execution . resume_with_fuel ( fuel) ? {
426- ExecProgress :: Completed ( values) => Ok ( ExecProgress :: Completed ( R :: from_wasm_value_tuple ( & values) ?) ) ,
424+ ExecProgress :: Completed ( values) => Ok ( ExecProgress :: Completed ( R :: from_wasm_values ( & values) ?) ) ,
427425 ExecProgress :: Suspended => Ok ( ExecProgress :: Suspended ) ,
428426 }
429427 }
@@ -435,53 +433,57 @@ impl<'store, R: FromWasmValueTuple> FuncExecutionTyped<'store, R> {
435433 /// time budget before returning [`ExecProgress::Suspended`].
436434 pub fn resume_with_time_budget ( & mut self , time_budget : crate :: std:: time:: Duration ) -> Result < ExecProgress < R > > {
437435 match self . execution . resume_with_time_budget ( time_budget) ? {
438- ExecProgress :: Completed ( values) => Ok ( ExecProgress :: Completed ( R :: from_wasm_value_tuple ( & values) ?) ) ,
436+ ExecProgress :: Completed ( values) => Ok ( ExecProgress :: Completed ( R :: from_wasm_values ( & values) ?) ) ,
439437 ExecProgress :: Suspended => Ok ( ExecProgress :: Suspended ) ,
440438 }
441439 }
442440}
443441
444- pub trait WasmTypesFromTuple {
442+ /// Describes the WebAssembly value types produced by a Rust value or tuple shape.
443+ pub trait ToWasmTypes {
444+ /// Return the flattened WebAssembly value types for this tuple shape.
445445 fn wasm_types ( ) -> Box < [ WasmType ] > ;
446446}
447447
448+ /// Describes the WebAssembly value types produced by a scalar Rust type.
448449pub trait ToWasmType {
449- fn to_wasm_type ( ) -> WasmType ;
450+ /// Return the single WebAssembly value type for this scalar type.
451+ fn wasm_type ( ) -> WasmType ;
450452}
451453
452454macro_rules! impl_scalar_wasm_traits {
453455 ( $( $T: ty => $val_ty: ident) ,+ $( , ) ?) => {
454456 $(
455457 impl ToWasmType for $T {
456458 #[ inline]
457- fn to_wasm_type ( ) -> WasmType {
459+ fn wasm_type ( ) -> WasmType {
458460 WasmType :: $val_ty
459461 }
460462 }
461463
462- impl WasmTypesFromTuple for $T {
464+ impl ToWasmTypes for $T {
463465 #[ inline]
464466 fn wasm_types( ) -> Box <[ WasmType ] > {
465467 Box :: new( [ WasmType :: $val_ty] )
466468 }
467469 }
468470
469- impl IntoWasmValueTuple for $T {
471+ impl IntoWasmValues for $T {
470472 #[ inline]
471- fn into_wasm_value_tuple ( self ) -> Vec <WasmValue > {
473+ fn into_wasm_values ( self ) -> Vec <WasmValue > {
472474 vec![ self . into( ) ]
473475 }
474476 }
475477
476- impl FromWasmValueTuple for $T {
478+ impl FromWasmValues for $T {
477479 #[ inline]
478- fn from_wasm_value_tuple ( values: & [ WasmValue ] ) -> Result <Self > {
480+ fn from_wasm_values ( values: & [ WasmValue ] ) -> Result <Self > {
479481 let value = * values
480482 . first( )
481483 . ok_or( Error :: Other ( "Not enough values in WasmValue vector" . to_string( ) ) ) ?;
482484 <$T>:: try_from( value) . map_err( |e| {
483485 Error :: Other ( format!(
484- "FromWasmValueTuple : Could not convert WasmValue to expected type: {:?}" ,
486+ "FromWasmValues : Could not convert WasmValue to expected type: {:?}" ,
485487 e
486488 ) )
487489 } )
@@ -493,34 +495,34 @@ macro_rules! impl_scalar_wasm_traits {
493495
494496macro_rules! impl_tuple_traits {
495497 ( $( $T: ident) ,+) => {
496- impl <$( $T) ,+> WasmTypesFromTuple for ( $( $T, ) +)
498+ impl <$( $T) ,+> ToWasmTypes for ( $( $T, ) +)
497499 where
498500 $( $T: ToWasmType , ) +
499501 {
500502 #[ inline]
501503 fn wasm_types( ) -> Box <[ WasmType ] > {
502- Box :: new( [ $( $T:: to_wasm_type ( ) , ) +] )
504+ Box :: new( [ $( $T:: wasm_type ( ) , ) +] )
503505 }
504506 }
505507
506- impl <$( $T) ,+> IntoWasmValueTuple for ( $( $T, ) +)
508+ impl <$( $T) ,+> IntoWasmValues for ( $( $T, ) +)
507509 where
508510 $( $T: Into <WasmValue >, ) +
509511 {
510512 #[ allow( non_snake_case) ]
511513 #[ inline]
512- fn into_wasm_value_tuple ( self ) -> Vec <WasmValue > {
514+ fn into_wasm_values ( self ) -> Vec <WasmValue > {
513515 let ( $( $T, ) +) = self ;
514516 vec![ $( $T. into( ) , ) +]
515517 }
516518 }
517519
518- impl <$( $T) ,+> FromWasmValueTuple for ( $( $T, ) +)
520+ impl <$( $T) ,+> FromWasmValues for ( $( $T, ) +)
519521 where
520522 $( $T: TryFrom <WasmValue , Error = ( ) >, ) +
521523 {
522524 #[ inline]
523- fn from_wasm_value_tuple ( values: & [ WasmValue ] ) -> Result <Self > {
525+ fn from_wasm_values ( values: & [ WasmValue ] ) -> Result <Self > {
524526 let mut iter = values. iter( ) ;
525527
526528 Ok ( (
@@ -530,7 +532,7 @@ macro_rules! impl_tuple_traits {
530532 . ok_or( Error :: Other ( "Not enough values in WasmValue vector" . to_string( ) ) ) ?
531533 )
532534 . map_err( |e| Error :: Other ( format!(
533- "FromWasmValueTuple : Could not convert WasmValue to expected type: {:?}" ,
535+ "FromWasmValues : Could not convert WasmValue to expected type: {:?}" ,
534536 e,
535537 ) ) ) ?,
536538 ) +
@@ -554,10 +556,6 @@ macro_rules! impl_tuple {
554556 $macro!( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 ) ;
555557 $macro!( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 ) ;
556558 $macro!( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 ) ;
557- $macro!( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 , T13 ) ;
558- $macro!( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 , T13 , T14 ) ;
559- $macro!( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 , T13 , T14 , T15 ) ;
560- $macro!( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10 , T11 , T12 , T13 , T14 , T15 , T16 ) ;
561559 } ;
562560}
563561
@@ -571,23 +569,125 @@ impl_scalar_wasm_traits!(
571569) ;
572570impl_tuple ! ( impl_tuple_traits) ;
573571
574- impl WasmTypesFromTuple for ( ) {
572+ /// A helper type for using tuples of arbitrary number of elements as function parameters or results,
573+ /// by concatenating the Wasm types of each element.
574+ ///
575+ /// This is useful when a function signature exceeds tuple arity 12. `tinywasm` only implements
576+ /// direct tuple conversions up to arity 12, but `WasmTupleChain` lets you describe longer
577+ /// signatures by combining smaller tuples at the type level.
578+ ///
579+ /// ## Example
580+ /// ```rust
581+ /// # fn main() -> tinywasm::Result<()> {
582+ /// # use tinywasm::{ModuleInstance, Store, WasmTupleChain};
583+ /// # let wasm = wat::parse_str(r#"
584+ /// # (module
585+ /// # (func (export "echo13")
586+ /// # (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
587+ /// # (result i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
588+ /// # local.get 0
589+ /// # local.get 1
590+ /// # local.get 2
591+ /// # local.get 3
592+ /// # local.get 4
593+ /// # local.get 5
594+ /// # local.get 6
595+ /// # local.get 7
596+ /// # local.get 8
597+ /// # local.get 9
598+ /// # local.get 10
599+ /// # local.get 11
600+ /// # local.get 12)
601+ /// # )
602+ /// # "#).expect("valid wat");
603+ /// # let module = tinywasm::parse_bytes(&wasm)?;
604+ /// # let mut store = Store::default();
605+ /// # let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
606+ ///
607+ /// type Params = WasmTupleChain<
608+ /// (i32, i32, i32, i32, i32, i32),
609+ /// (i32, i32, i32, i32, i32, i32, i32),
610+ /// >;
611+ /// type Results = WasmTupleChain<
612+ /// (i32, i32, i32, i32, i32, i32),
613+ /// (i32, i32, i32, i32, i32, i32, i32),
614+ /// >;
615+ ///
616+ /// let echo13 = instance.func::<Params, Results>(&store, "echo13")?;
617+ /// let result = echo13.call(&mut store, ((1, 2, 3, 4, 5, 6), (7, 8, 9, 10, 11, 12, 13)).into())?;
618+ /// assert_eq!(result.into_inner(), ((1, 2, 3, 4, 5, 6), (7, 8, 9, 10, 11, 12, 13)));
619+ /// # Ok(())
620+ /// # }
621+ /// ```
622+ #[ derive( Default ) ]
623+ pub struct WasmTupleChain < T1 , T2 > ( T1 , T2 ) ;
624+
625+ impl < T1 , T2 > WasmTupleChain < T1 , T2 > {
626+ /// Create a new concatenated tuple wrapper.
627+ pub const fn new ( left : T1 , right : T2 ) -> Self {
628+ Self ( left, right)
629+ }
630+
631+ /// Split the wrapper back into its two component values.
632+ pub fn into_inner ( self ) -> ( T1 , T2 ) {
633+ ( self . 0 , self . 1 )
634+ }
635+ }
636+
637+ impl < T1 , T2 > From < ( T1 , T2 ) > for WasmTupleChain < T1 , T2 > {
638+ fn from ( ( left, right) : ( T1 , T2 ) ) -> Self {
639+ Self :: new ( left, right)
640+ }
641+ }
642+
643+ impl < T1 : ToWasmTypes , T2 : ToWasmTypes > ToWasmTypes for WasmTupleChain < T1 , T2 > {
644+ #[ inline]
645+ fn wasm_types ( ) -> Box < [ WasmType ] > {
646+ let mut types = Vec :: new ( ) ;
647+ types. extend_from_slice ( & T1 :: wasm_types ( ) ) ;
648+ types. extend_from_slice ( & T2 :: wasm_types ( ) ) ;
649+ types. into_boxed_slice ( )
650+ }
651+ }
652+
653+ impl < T1 : IntoWasmValues , T2 : IntoWasmValues > IntoWasmValues for WasmTupleChain < T1 , T2 > {
654+ #[ inline]
655+ fn into_wasm_values ( self ) -> Vec < WasmValue > {
656+ let ( left, right) = self . into_inner ( ) ;
657+ let mut values = Vec :: new ( ) ;
658+ values. extend ( left. into_wasm_values ( ) ) ;
659+ values. extend ( right. into_wasm_values ( ) ) ;
660+ values
661+ }
662+ }
663+
664+ impl < T1 : FromWasmValues + ToWasmTypes , T2 : FromWasmValues > FromWasmValues for WasmTupleChain < T1 , T2 > {
665+ #[ inline]
666+ fn from_wasm_values ( values : & [ WasmValue ] ) -> Result < Self > {
667+ let left_len = T1 :: wasm_types ( ) . len ( ) ;
668+ let left = T1 :: from_wasm_values ( & values[ ..values. len ( ) . min ( left_len) ] ) ?;
669+ let right = T2 :: from_wasm_values ( values. get ( left_len..) . unwrap_or ( & [ ] ) ) ?;
670+ Ok ( Self :: new ( left, right) )
671+ }
672+ }
673+
674+ impl ToWasmTypes for ( ) {
575675 #[ inline]
576676 fn wasm_types ( ) -> Box < [ WasmType ] > {
577677 Box :: new ( [ ] )
578678 }
579679}
580680
581- impl IntoWasmValueTuple for ( ) {
681+ impl IntoWasmValues for ( ) {
582682 #[ inline]
583- fn into_wasm_value_tuple ( self ) -> Vec < WasmValue > {
683+ fn into_wasm_values ( self ) -> Vec < WasmValue > {
584684 vec ! [ ]
585685 }
586686}
587687
588- impl FromWasmValueTuple for ( ) {
688+ impl FromWasmValues for ( ) {
589689 #[ inline]
590- fn from_wasm_value_tuple ( _values : & [ WasmValue ] ) -> Result < Self > {
690+ fn from_wasm_values ( _values : & [ WasmValue ] ) -> Result < Self > {
591691 Ok ( ( ) )
592692 }
593693}
0 commit comments