1use anyhow::Result;
2use std::time::{Duration, Instant};
3
4use crate::{limits::StoreLimitsAsync, State, WasmtimeEngine};
5
6#[cfg(doc)]
7use crate::EngineBuilder;
8
9pub struct Store<T: 'static> {
16 inner: wasmtime::Store<T>,
17 epoch_tick_interval: Duration,
18}
19
20impl<T: 'static> Store<T> {
21 pub fn set_deadline(&mut self, deadline: Instant) {
29 let now = Instant::now();
30 let duration = deadline - now;
31 let ticks = if duration.is_zero() {
32 tracing::warn!("Execution deadline set in past: {deadline:?} < {now:?}");
33 0
34 } else {
35 let ticks = duration.as_micros() / self.epoch_tick_interval.as_micros();
36 let ticks = ticks.min(u64::MAX as u128) as u64;
37 ticks + 1 };
39 self.inner.set_epoch_deadline(ticks);
40 }
41
42 pub fn data(&self) -> &T {
44 self.inner.data()
45 }
46
47 pub fn data_mut(&mut self) -> &mut T {
49 self.inner.data_mut()
50 }
51
52 pub fn into_inner(self) -> wasmtime::Store<T> {
54 self.inner
55 }
56}
57
58impl<T: 'static> AsRef<wasmtime::Store<T>> for Store<T> {
59 fn as_ref(&self) -> &wasmtime::Store<T> {
60 &self.inner
61 }
62}
63
64impl<T: 'static> AsMut<wasmtime::Store<T>> for Store<T> {
65 fn as_mut(&mut self) -> &mut wasmtime::Store<T> {
66 &mut self.inner
67 }
68}
69
70impl<T: 'static> wasmtime::AsContext for Store<T> {
71 type Data = T;
72
73 fn as_context(&self) -> wasmtime::StoreContext<'_, Self::Data> {
74 self.inner.as_context()
75 }
76}
77
78impl<T: 'static> wasmtime::AsContextMut for Store<T> {
79 fn as_context_mut(&mut self) -> wasmtime::StoreContextMut<'_, Self::Data> {
80 self.inner.as_context_mut()
81 }
82}
83
84pub struct StoreBuilder {
88 engine: WasmtimeEngine,
89 epoch_tick_interval: Duration,
90 store_limits: StoreLimitsAsync,
91}
92
93impl StoreBuilder {
94 pub(crate) fn new(engine: WasmtimeEngine, epoch_tick_interval: Duration) -> Self {
96 Self {
97 engine,
98 epoch_tick_interval,
99 store_limits: StoreLimitsAsync::default(),
100 }
101 }
102
103 pub fn max_memory_size(&mut self, max_memory_size: usize) {
108 self.store_limits = StoreLimitsAsync::new(Some(max_memory_size), None);
109 }
110
111 pub fn build<T: AsState>(self, mut data: T) -> Result<Store<T>> {
116 data.as_state().store_limits = self.store_limits;
117
118 let mut inner = wasmtime::Store::new(&self.engine, data);
119 inner.limiter_async(|data| &mut data.as_state().store_limits);
120
121 inner.set_epoch_deadline(u64::MAX / 2);
126
127 Ok(Store {
128 inner,
129 epoch_tick_interval: self.epoch_tick_interval,
130 })
131 }
132}
133
134pub trait AsState {
137 fn as_state(&mut self) -> &mut State;
139}
140
141impl AsState for State {
142 fn as_state(&mut self) -> &mut State {
143 self
144 }
145}