wasmtime_provider/
builder.rs1use crate::errors::{Error, Result};
2use crate::{EpochDeadlines, ResourceLimits, 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 resource_limits: Option<ResourceLimits>,
21}
22
23#[allow(deprecated)]
24impl<'a> WasmtimeEngineProviderBuilder<'a> {
25 #[must_use]
27 pub fn new() -> Self {
28 Default::default()
29 }
30
31 #[must_use]
33 pub fn module_bytes(mut self, module_bytes: &'a [u8]) -> Self {
34 self.module_bytes = Some(module_bytes);
35 self
36 }
37
38 #[must_use]
44 pub fn module(mut self, module: wasmtime::Module) -> Self {
45 self.module = Some(module);
46 self
47 }
48
49 #[must_use]
57 pub fn engine(mut self, engine: wasmtime::Engine) -> Self {
58 self.engine = Some(engine);
59 self
60 }
61
62 #[cfg(feature = "wasi")]
64 #[cfg_attr(docsrs, doc(cfg(feature = "wasi")))]
65 #[must_use]
66 pub fn wasi_params(mut self, wasi: wapc::WasiParams) -> Self {
67 self.wasi_params = Some(wasi);
68 self
69 }
70
71 #[cfg(feature = "cache")]
77 #[cfg_attr(docsrs, doc(cfg(feature = "cache")))]
78 #[must_use]
79 pub fn enable_cache(mut self, path: Option<&std::path::Path>) -> Self {
80 self.cache_enabled = true;
81 self.cache_path = path.map(|p| p.to_path_buf());
82 self
83 }
84
85 #[must_use]
92 pub fn enable_epoch_interruptions(mut self, epoch_deadlines: EpochDeadlines) -> Self {
93 self.epoch_deadlines = Some(epoch_deadlines);
94 self
95 }
96
97 #[must_use]
105 pub fn enable_resource_limits(mut self, resource_limits: ResourceLimits) -> Self {
106 self.resource_limits = Some(resource_limits);
107 self
108 }
109
110 pub fn build_pre(&self) -> Result<WasmtimeEngineProviderPre> {
114 if self.module_bytes.is_some() && self.module.is_some() {
115 return Err(Error::BuilderInvalidConfig(
116 "`module_bytes` and `module` cannot be provided at the same time".to_owned(),
117 ));
118 }
119 if self.module_bytes.is_none() && self.module.is_none() {
120 return Err(Error::BuilderInvalidConfig(
121 "Neither `module_bytes` nor `module` have been provided".to_owned(),
122 ));
123 }
124
125 let pre = match &self.engine {
126 Some(e) => {
127 let module = self.module_bytes.as_ref().map_or_else(
128 || Ok(self.module.as_ref().unwrap().clone()),
129 |module_bytes| wasmtime::Module::new(e, module_bytes),
130 )?;
131
132 cfg_if::cfg_if! {
139 if #[cfg(feature = "wasi")] {
140 WasmtimeEngineProviderPre::new(e.clone(), module, self.wasi_params.clone(), self.resource_limits)
141 } else {
142 WasmtimeEngineProviderPre::new(e.clone(), module, self.resource_limits)
143 }
144 }
145 }
146 None => {
147 let mut config = wasmtime::Config::default();
148 if self.epoch_deadlines.is_some() {
149 config.epoch_interruption(true);
150 }
151
152 cfg_if::cfg_if! {
153 if #[cfg(feature = "cache")] {
154 if self.cache_enabled {
155 config.strategy(wasmtime::Strategy::Cranelift);
156 let cache = self.cache_path.as_ref().map_or_else(
157 || wasmtime::CacheConfig::from_file(None).and_then(wasmtime::Cache::new),
158 |cache_path| {
159 let mut cache_config = wasmtime::CacheConfig::new();
160 cache_config.with_directory(cache_path);
161 wasmtime::Cache::new(cache_config)
162 }
163 ).map_or_else(
164 |e| {
165 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.");
166 None
167 },
168 Some,
169 );
170 config.cache(cache);
171 }
172 }
173 }
174
175 let engine = wasmtime::Engine::new(&config)?;
176
177 let module = self.module_bytes.as_ref().map_or_else(
178 || Ok(self.module.as_ref().unwrap().clone()),
179 |module_bytes| wasmtime::Module::new(&engine, module_bytes),
180 )?;
181
182 cfg_if::cfg_if! {
183 if #[cfg(feature = "wasi")] {
184 WasmtimeEngineProviderPre::new(engine, module, self.wasi_params.clone(), self.resource_limits)
185 } else {
186 WasmtimeEngineProviderPre::new(engine, module, self.resource_limits)
187
188 }
189 }
190 }
191 }?;
192
193 Ok(pre)
194 }
195
196 pub fn build(&self) -> Result<WasmtimeEngineProvider> {
198 let pre = self.build_pre()?;
199 pre.rehydrate(self.epoch_deadlines)
200 }
201
202 #[cfg(feature = "async")]
209 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
210 pub fn build_async_pre(&self) -> Result<WasmtimeEngineProviderAsyncPre> {
211 if self.module_bytes.is_some() && self.module.is_some() {
212 return Err(Error::BuilderInvalidConfig(
213 "`module_bytes` and `module` cannot be provided at the same time".to_owned(),
214 ));
215 }
216 if self.module_bytes.is_none() && self.module.is_none() {
217 return Err(Error::BuilderInvalidConfig(
218 "Neither `module_bytes` nor `module` have been provided".to_owned(),
219 ));
220 }
221
222 let pre = match &self.engine {
223 Some(e) => {
224 let module = self.module_bytes.as_ref().map_or_else(
225 || Ok(self.module.as_ref().unwrap().clone()),
226 |module_bytes| wasmtime::Module::new(e, module_bytes),
227 )?;
228
229 cfg_if::cfg_if! {
236 if #[cfg(feature = "wasi")] {
237 WasmtimeEngineProviderAsyncPre::new(e.clone(), module, self.wasi_params.clone(), self.epoch_deadlines, self.resource_limits)
238 } else {
239 WasmtimeEngineProviderAsyncPre::new(e.clone(), module, self.epoch_deadlines, self.resource_limits)
240 }
241 }
242 }
243 None => {
244 let mut config = wasmtime::Config::default();
245 config.async_support(true);
246
247 if self.epoch_deadlines.is_some() {
248 config.epoch_interruption(true);
249 }
250
251 cfg_if::cfg_if! {
252 if #[cfg(feature = "cache")] {
253 if self.cache_enabled {
254 config.strategy(wasmtime::Strategy::Cranelift);
255 let cache = self.cache_path.as_ref().map_or_else(
256 || wasmtime::CacheConfig::from_file(None).and_then(wasmtime::Cache::new),
257 |cache_path| {
258 let mut cache_config = wasmtime::CacheConfig::new();
259 cache_config.with_directory(cache_path);
260 wasmtime::Cache::new(cache_config)
261 }
262 ).map_or_else(
263 |e| {
264 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.");
265 None
266 },
267 Some,
268 );
269 config.cache(cache);
270 }
271 }
272 }
273
274 let engine = wasmtime::Engine::new(&config)?;
275
276 let module = self.module_bytes.as_ref().map_or_else(
277 || Ok(self.module.as_ref().unwrap().clone()),
278 |module_bytes| wasmtime::Module::new(&engine, module_bytes),
279 )?;
280
281 cfg_if::cfg_if! {
282 if #[cfg(feature = "wasi")] {
283 WasmtimeEngineProviderAsyncPre::new(engine, module, self.wasi_params.clone(), self.epoch_deadlines, self.resource_limits)
284 } else {
285 WasmtimeEngineProviderAsyncPre::new(engine, module, self.epoch_deadlines, self.resource_limits)
286 }
287 }
288 }
289 }?;
290
291 Ok(pre)
292 }
293
294 #[cfg(feature = "async")]
296 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
297 pub fn build_async(&self) -> Result<WasmtimeEngineProviderAsync> {
298 let pre = self.build_async_pre()?;
299 pre.rehydrate()
300 }
301}