1+ #[ cfg( feature = "state" ) ]
2+ use alloc:: collections:: BTreeMap ;
13use alloc:: { boxed:: Box , format, vec:: Vec } ;
4+ #[ cfg( feature = "state" ) ]
5+ use core:: any:: { Any , TypeId } ;
26use core:: hint:: cold_path;
37use tinywasm_types:: * ;
48
@@ -110,6 +114,25 @@ pub trait ResourceLimiter: Send + Sync {
110114 }
111115}
112116
117+ /// A value stored as host state.
118+ #[ doc( hidden) ]
119+ #[ cfg( all( feature = "state" , not( feature = "send" ) ) ) ]
120+ pub trait StoreState : Any { }
121+ #[ cfg( all( feature = "state" , not( feature = "send" ) ) ) ]
122+ impl < T : Any > StoreState for T { }
123+
124+ /// A value stored as host state.
125+ #[ doc( hidden) ]
126+ #[ cfg( all( feature = "state" , feature = "send" ) ) ]
127+ pub trait StoreState : Any + Send { }
128+ #[ cfg( all( feature = "state" , feature = "send" ) ) ]
129+ impl < T : Any + Send > StoreState for T { }
130+
131+ #[ cfg( all( feature = "state" , not( feature = "send" ) ) ) ]
132+ type StoredState = dyn Any ;
133+ #[ cfg( all( feature = "state" , feature = "send" ) ) ]
134+ type StoredState = dyn Any + Send ;
135+
113136/// Runtime state used by WebAssembly instances and host functions.
114137///
115138/// ## Example
@@ -133,6 +156,8 @@ pub struct Store {
133156 pub ( crate ) call_stack : CallStack ,
134157 pub ( crate ) value_stack : ValueStack ,
135158 value_scratch : ValueScratch ,
159+ #[ cfg( feature = "state" ) ]
160+ host_state : BTreeMap < TypeId , Box < StoredState > > ,
136161}
137162
138163#[ derive( Default ) ]
@@ -238,9 +263,47 @@ impl Store {
238263 engine,
239264 execution_fuel : 0 ,
240265 execution_active : false ,
266+ #[ cfg( feature = "state" ) ]
267+ host_state : BTreeMap :: new ( ) ,
241268 }
242269 }
243270
271+ /// Adds host state to this store.
272+ ///
273+ /// Host callbacks can access the value through [`Store::state`] and
274+ /// [`Store::state_mut`]. If state of the same type already exists, this
275+ /// method replaces it.
276+ ///
277+ /// # Example
278+ ///
279+ /// ```rust
280+ /// use tinywasm::Store;
281+ ///
282+ /// struct AppState {
283+ /// requests: usize,
284+ /// }
285+ ///
286+ /// let store = Store::default().with_state(AppState { requests: 0 });
287+ /// assert_eq!(store.state::<AppState>().unwrap().requests, 0);
288+ /// ```
289+ #[ cfg( feature = "state" ) ]
290+ pub fn with_state < T : StoreState > ( mut self , state : T ) -> Self {
291+ self . host_state . insert ( TypeId :: of :: < T > ( ) , Box :: new ( state) ) ;
292+ self
293+ }
294+
295+ /// Get host state.
296+ #[ cfg( feature = "state" ) ]
297+ pub fn state < T : StoreState > ( & self ) -> Option < & T > {
298+ self . host_state . get ( & TypeId :: of :: < T > ( ) ) . and_then ( |state| state. downcast_ref ( ) )
299+ }
300+
301+ /// Get mutable access to host state.
302+ #[ cfg( feature = "state" ) ]
303+ pub fn state_mut < T : StoreState > ( & mut self ) -> Option < & mut T > {
304+ self . host_state . get_mut ( & TypeId :: of :: < T > ( ) ) . and_then ( |state| state. downcast_mut ( ) )
305+ }
306+
244307 pub ( crate ) const fn id ( & self ) -> StoreId {
245308 self . id
246309 }
0 commit comments