wasmtime_provider/
builder.rs1use crate::errors::{Error, Result};
2use crate::{EpochDeadlines, WasmtimeEngineProvider, WasmtimeEngineProviderPre};
3#[cfg(feature = "async")]
4use crate::{WasmtimeEngineProviderAsync, WasmtimeEngineProviderAsyncPre};
5
6#[allow(missing_debug_implementations)]
8#[derive(Default)]
9pub struct WasmtimeEngineProviderBuilder<'a> {
10 engine: Option<wasmtime::Engine>,
11 module: Option<wasmtime::Module>,
12 module_bytes: Option<&'a [u8]>,
13 #[cfg(feature = "cache")]
14 cache_enabled: bool,
15 #[cfg(feature = "cache")]
16 cache_path: Option<std::path::PathBuf>,
17 #[cfg(feature = "wasi")]
18 wasi_params: Option<wapc::WasiParams>,
19 epoch_deadlines: Option<EpochDeadlines>,
20}
21
22#[allow(deprecated)]
23impl<'a> WasmtimeEngineProviderBuilder<'a> {
24 #[must_use]
26 pub fn new() -> Self {
27 Default::default()
28 }
29
30 #[must_use]
32 pub fn module_bytes(mut self, module_bytes: &'a [u8]) -> Self {
33 self.module_bytes = Some(module_bytes);
34 self
35 }
36
37 #[must_use]
43 pub fn module(mut self, module: wasmtime::Module) -> Self {
44 self.module = Some(module);
45 self
46 }
47
48 #[must_use]
56 pub fn engine(mut self, engine: wasmtime::Engine) -> Self {
57 self.engine = Some(engine);
58 self
59 }
60
61 #[cfg(feature = "wasi")]
63 #[cfg_attr(docsrs, doc(cfg(feature = "wasi")))]
64 #[must_use]
65 pub fn wasi_params(mut self, wasi: wapc::WasiParams) -> Self {
66 self.wasi_params = Some(wasi);
67 self
68 }
69
70 #[cfg(feature = "cache")]
76 #[cfg_attr(docsrs, doc(cfg(feature = "cache")))]
77 #[must_use]
78 pub fn enable_cache(mut self, path: Option<&std::path::Path>) -> Self {
79 self.cache_enabled = true;
80 self.cache_path = path.map(|p| p.to_path_buf());
81 self
82 }
83
84 #[must_use]
91 pub fn enable_epoch_interruptions(mut self, epoch_deadlines: EpochDeadlines) -> Self {
92 self.epoch_deadlines = Some(epoch_deadlines);
93 self
94 }
95
96 pub fn build_pre(&self) -> Result<WasmtimeEngineProviderPre> {
100 if self.module_bytes.is_some() && self.module.is_some() {
101 return Err(Error::BuilderInvalidConfig(
102 "`module_bytes` and `module` cannot be provided at the same time".to_owned(),
103 ));
104 }
105 if self.module_bytes.is_none() && self.module.is_none() {
106 return Err(Error::BuilderInvalidConfig(
107 "Neither `module_bytes` nor `module` have been provided".to_owned(),
108 ));
109 }
110
111 let pre = match &self.engine {
112 Some(e) => {
113 let module = self.module_bytes.as_ref().map_or_else(
114 || Ok(self.module.as_ref().unwrap().clone()),
115 |module_bytes| wasmtime::Module::new(e, module_bytes),
116 )?;
117
118 cfg_if::cfg_if! {
125 if #[cfg(feature = "wasi")] {
126 WasmtimeEngineProviderPre::new(e.clone(), module, self.wasi_params.clone())
127 } else {
128 WasmtimeEngineProviderPre::new(e.clone(), module)
129 }
130 }
131 }
132 None => {
133 let mut config = wasmtime::Config::default();
134 if self.epoch_deadlines.is_some() {
135 config.epoch_interruption(true);
136 }
137
138 cfg_if::cfg_if! {
139 if #[cfg(feature = "cache")] {
140 if self.cache_enabled {
141 config.strategy(wasmtime::Strategy::Cranelift);
142 let cache = self.cache_path.as_ref().map_or_else(
143 || wasmtime::CacheConfig::from_file(None).and_then(wasmtime::Cache::new),
144 |cache_path| {
145 let mut cache_config = wasmtime::CacheConfig::new();
146 cache_config.with_directory(cache_path);
147 wasmtime::Cache::new(cache_config)
148 }
149 ).map_or_else(
150 |e| {
151 log::warn!("Wasmtime cache configuration not found ({e}). Repeated loads will speed up significantly with a cache configuration. See https://docs.wasmtime.dev/cli-cache.html for more information.");
152 None
153 },
154 Some,
155 );
156 config.cache(cache);
157 }
158 }
159 }
160
161 let engine = wasmtime::Engine::new(&config)?;
162
163 let module = self.module_bytes.as_ref().map_or_else(
164 || Ok(self.module.as_ref().unwrap().clone()),
165 |module_bytes| wasmtime::Module::new(&engine, module_bytes),
166 )?;
167
168 cfg_if::cfg_if! {
169 if #[cfg(feature = "wasi")] {
170 WasmtimeEngineProviderPre::new(engine, module, self.wasi_params.clone())
171 } else {
172 WasmtimeEngineProviderPre::new(engine, module)
173
174 }
175 }
176 }
177 }?;
178
179 Ok(pre)
180 }
181
182 pub fn build(&self) -> Result<WasmtimeEngineProvider> {
184 let pre = self.build_pre()?;
185 pre.rehydrate(self.epoch_deadlines)
186 }
187
188 #[cfg(feature = "async")]
195 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
196 pub fn build_async_pre(&self) -> Result<WasmtimeEngineProviderAsyncPre> {
197 if self.module_bytes.is_some() && self.module.is_some() {
198 return Err(Error::BuilderInvalidConfig(
199 "`module_bytes` and `module` cannot be provided at the same time".to_owned(),
200 ));
201 }
202 if self.module_bytes.is_none() && self.module.is_none() {
203 return Err(Error::BuilderInvalidConfig(
204 "Neither `module_bytes` nor `module` have been provided".to_owned(),
205 ));
206 }
207
208 let pre = match &self.engine {
209 Some(e) => {
210 let module = self.module_bytes.as_ref().map_or_else(
211 || Ok(self.module.as_ref().unwrap().clone()),
212 |module_bytes| wasmtime::Module::new(e, module_bytes),
213 )?;
214
215 cfg_if::cfg_if! {
222 if #[cfg(feature = "wasi")] {
223 WasmtimeEngineProviderAsyncPre::new(e.clone(), module, self.wasi_params.clone(), self.epoch_deadlines)
224 } else {
225 WasmtimeEngineProviderAsyncPre::new(e.clone(), module, self.epoch_deadlines)
226 }
227 }
228 }
229 None => {
230 let mut config = wasmtime::Config::default();
231 config.async_support(true);
232
233 if self.epoch_deadlines.is_some() {
234 config.epoch_interruption(true);
235 }
236
237 cfg_if::cfg_if! {
238 if #[cfg(feature = "cache")] {
239 if self.cache_enabled {
240 config.strategy(wasmtime::Strategy::Cranelift);
241 let cache = self.cache_path.as_ref().map_or_else(
242 || wasmtime::CacheConfig::from_file(None).and_then(wasmtime::Cache::new),
243 |cache_path| {
244 let mut cache_config = wasmtime::CacheConfig::new();
245 cache_config.with_directory(cache_path);
246 wasmtime::Cache::new(cache_config)
247 }
248 ).map_or_else(
249 |e| {
250 log::warn!("Wasmtime cache configuration not found ({e}). Repeated loads will speed up significantly with a cache configuration. See https://docs.wasmtime.dev/cli-cache.html for more information.");
251 None
252 },
253 Some,
254 );
255 config.cache(cache);
256 }
257 }
258 }
259
260 let engine = wasmtime::Engine::new(&config)?;
261
262 let module = self.module_bytes.as_ref().map_or_else(
263 || Ok(self.module.as_ref().unwrap().clone()),
264 |module_bytes| wasmtime::Module::new(&engine, module_bytes),
265 )?;
266
267 cfg_if::cfg_if! {
268 if #[cfg(feature = "wasi")] {
269 WasmtimeEngineProviderAsyncPre::new(engine, module, self.wasi_params.clone(), self.epoch_deadlines)
270 } else {
271 WasmtimeEngineProviderAsyncPre::new(engine, module, self.epoch_deadlines)
272 }
273 }
274 }
275 }?;
276
277 Ok(pre)
278 }
279
280 #[cfg(feature = "async")]
282 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
283 pub fn build_async(&self) -> Result<WasmtimeEngineProviderAsync> {
284 let pre = self.build_async_pre()?;
285 pre.rehydrate()
286 }
287}