Skip to content
This repository was archived by the owner on Oct 3, 2025. It is now read-only.

Commit b49c1c4

Browse files
committed
support suspending start function when instantiating module
1 parent 9a90550 commit b49c1c4

File tree

4 files changed

+77
-4
lines changed

4 files changed

+77
-4
lines changed

crates/tinywasm/src/coro.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ pub enum SuspendReason {
2424
/// async should_suspend flag was set
2525
/// host shouldn't provide resume argument when calling resume
2626
SuspendedFlag,
27+
28+
// possible others: delimited continuations proposal, debugger breakpoint, out of fuel
2729
}
2830

2931
/// result of a function that might pause in the middle and yield
@@ -43,6 +45,7 @@ pub enum PotentialCoroCallResult<R, State>
4345
/// doesn't need to have state, since it's contained in self
4446
#[derive(Debug)]
4547
pub enum CoroStateResumeResult<R> {
48+
/// CoroState has finished
4649
/// after this CoroState::resume can't be called again on that CoroState
4750
Return(R),
4851

crates/tinywasm/src/instance.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use alloc::{boxed::Box, format, rc::Rc, string::ToString};
22
use tinywasm_types::*;
33

44
use crate::func::{FromWasmValueTuple, IntoWasmValueTuple};
5-
use crate::{Error, FuncHandle, FuncHandleTyped, Imports, MemoryRef, MemoryRefMut, Module, Result, Store};
5+
use crate::{Error, FuncHandle, FuncHandleTyped, Imports, MemoryRef, MemoryRefMut, Module, PotentialCoroCallResult, Result, Store, SuspendFunc};
66

77
/// An instanciated WebAssembly module
88
///
@@ -263,4 +263,18 @@ impl ModuleInstance {
263263
let _ = func.call(store, &[])?;
264264
Ok(Some(()))
265265
}
266+
267+
/// Invoke the start function of the module
268+
///
269+
/// Returns None if the module has no start function
270+
/// If start function suspends, returns SuspededFunc.
271+
/// Only when it finishes can this module instance be considered instantiated
272+
pub fn start_coro(&self, store: &mut Store) -> Result<Option<PotentialCoroCallResult<(), SuspendFunc>>> {
273+
let Some(func) = self.start_func(store)? else {
274+
return Ok(None);
275+
};
276+
277+
let res = func.call_coro(store, &[])?;
278+
Ok(Some(res.map_result(|_|{()})))
279+
}
266280
}

crates/tinywasm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub use error::*;
9696
pub use func::{FuncHandle, FuncHandleTyped, SuspendFunc};
9797
pub use imports::*;
9898
pub use instance::ModuleInstance;
99-
pub use module::Module;
99+
pub use module::{IncompleteModule, Module};
100100
pub use reference::*;
101101
pub use store::*;
102102

crates/tinywasm/src/module.rs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::{Imports, ModuleInstance, Result, Store};
2-
use tinywasm_types::TinyWasmModule;
1+
use crate::{CoroState, Imports, ModuleInstance, PotentialCoroCallResult, Result, Store, SuspendFunc};
2+
use tinywasm_types::{ResumeArgument, TinyWasmModule};
33

44
/// A WebAssembly Module
55
///
@@ -56,4 +56,60 @@ impl Module {
5656
let _ = instance.start(store)?;
5757
Ok(instance)
5858
}
59+
60+
/// same as [Self::instantiate] but accounts for possibility of start function suspending, in which case it returns
61+
/// [PotentialCoroCallResult::Suspended]. You can call [CoroState::resume] on it at any time to resume instantiation
62+
pub fn instantiate_coro(
63+
self,
64+
store: &mut Store,
65+
imports: Option<Imports>,
66+
) -> Result<PotentialCoroCallResult<ModuleInstance, IncompleteModule>> {
67+
let instance = ModuleInstance::instantiate(store, self, imports)?;
68+
let core_res = match instance.start_coro(store)? {
69+
Some(res) => res,
70+
None => return Ok(PotentialCoroCallResult::Return(instance)),
71+
};
72+
match core_res {
73+
crate::PotentialCoroCallResult::Return(_) => return Ok(PotentialCoroCallResult::Return(instance)),
74+
crate::PotentialCoroCallResult::Suspended(suspend_reason, state) => {
75+
return Ok(PotentialCoroCallResult::Suspended(
76+
suspend_reason,
77+
IncompleteModule(Some(HitTheFloor(instance, state))),
78+
))
79+
}
80+
}
81+
}
82+
}
83+
84+
/// a corostate that results in [ModuleInstance] when finished
85+
#[derive(Debug)]
86+
pub struct IncompleteModule(Option<HitTheFloor>);
87+
88+
#[derive(Debug)]
89+
struct HitTheFloor(ModuleInstance, SuspendFunc);
90+
91+
impl<'a> CoroState<ModuleInstance, &'a mut Store> for IncompleteModule {
92+
fn resume(&mut self, ctx: &mut Store, arg: ResumeArgument) -> Result<crate::CoroStateResumeResult<ModuleInstance>> {
93+
let mut body: HitTheFloor = match self.0.take() {
94+
Some(body) => body,
95+
None => return Err(crate::Error::InvalidResume),
96+
};
97+
let coro_res = match body.1.resume(ctx, arg) {
98+
Ok(res) => res,
99+
Err(e) => {
100+
self.0 = Some(body);
101+
return Err(e);
102+
}
103+
};
104+
match coro_res {
105+
crate::CoroStateResumeResult::Return(_) => {
106+
let res = body.0;
107+
Ok(crate::CoroStateResumeResult::Return(res))
108+
}
109+
crate::CoroStateResumeResult::Suspended(suspend_reason) => {
110+
self.0 = Some(body); // ...once told me
111+
Ok(crate::CoroStateResumeResult::Suspended(suspend_reason))
112+
}
113+
}
114+
}
59115
}

0 commit comments

Comments
 (0)