Skip to main content

zwasm_sdk/
config.rs

1use crate::error;
2use crate::ffi;
3use zwasm_sys as sys;
4
5/* ================================================================
6 * Configuration (optional)
7 * ================================================================ */
8
9/// Runtime configuration for zwasm modules.
10///
11/// Allows fine-grained control over memory allocation, fuel, timeouts, and resource limits.
12/// Used to customize the execution environment for a [`Module`](crate::Module).
13pub struct Config {
14    pub(crate) ptr: *mut sys::zwasm_config_t,
15    allocator: Option<Box<ConfigAllocator>>,
16    _not_send_sync: std::marker::PhantomData<std::rc::Rc<()>>,
17}
18
19impl Config {
20    /// Creates a new runtime configuration for zwasm modules.
21    ///
22    /// Use this to control memory allocation, fuel, timeouts, and other resource limits.
23    pub fn new() -> Result<Self, error::ZwasmError> {
24        let ptr = unsafe { sys::zwasm_config_new() };
25
26        if ptr.is_null() {
27            Err(error::last_error()
28                .unwrap_or_else(|| error::ZwasmError("Unknown error".to_string())))
29        } else {
30            Ok(Config {
31                ptr,
32                allocator: None,
33                _not_send_sync: std::marker::PhantomData,
34            })
35        }
36    }
37
38    /// Sets custom memory allocation hooks for the zwasm runtime.
39    ///
40    /// Allows you to override all memory allocation for Wasm execution. Useful for sandboxing or tracking allocations.
41    ///
42    /// # Safety
43    /// The provided callbacks must obey allocator semantics for all `(size, align)` pairs
44    /// that the runtime may request. Returning invalid pointers or violating alignment/
45    /// deallocation contracts can cause undefined behavior in native code.
46    pub fn set_allocator<F, G>(&mut self, alloc_fn: F, free_fn: G)
47    where
48        F: Fn(usize, usize) -> *mut std::ffi::c_void + Send + Sync + 'static,
49        G: Fn(*mut std::ffi::c_void, usize, usize) + Send + Sync + 'static,
50    {
51        let mut allocator = Box::new(ConfigAllocator {
52            alloc: Box::new(alloc_fn),
53            free: Box::new(free_fn),
54        });
55
56        let env = &mut *allocator as *mut ConfigAllocator as *mut std::ffi::c_void;
57
58        unsafe {
59            sys::zwasm_config_set_allocator(
60                self.ptr,
61                Some(ffi::config_allocator_alloc_trampoline),
62                Some(ffi::config_allocator_free_trampoline),
63                env,
64            );
65        }
66
67        self.allocator = Some(allocator);
68    }
69
70    /// Sets the execution fuel limit for the module.
71    ///
72    /// Fuel limits restrict the number of instructions a module can execute before trapping.
73    pub fn set_fuel(&mut self, fuel: u64) {
74        unsafe {
75            sys::zwasm_config_set_fuel(self.ptr, fuel);
76        }
77    }
78
79    /// Sets the execution timeout (in milliseconds) for the module.
80    ///
81    /// Execution will be interrupted if the timeout is exceeded.
82    pub fn set_timeout(&mut self, timeout_ms: u64) {
83        unsafe {
84            sys::zwasm_config_set_timeout(self.ptr, timeout_ms);
85        }
86    }
87
88    /// Sets the maximum linear memory (in bytes) for the module.
89    ///
90    /// Prevents Wasm modules from growing memory beyond this limit.
91    pub fn set_max_memory(&mut self, max_memory: u64) {
92        unsafe {
93            sys::zwasm_config_set_max_memory(self.ptr, max_memory);
94        }
95    }
96
97    /// Forces interpreter mode (disables JIT) when `true`.
98    ///
99    /// Useful for debugging or running on unsupported platforms.
100    pub fn set_force_interpreter(&mut self, force: bool) {
101        unsafe {
102            sys::zwasm_config_set_force_interpreter(self.ptr, force);
103        }
104    }
105
106    /// Enables or disables cancellation support for the module.
107    ///
108    /// When enabled, execution can be cancelled via [`Module::cancel`](crate::Module::cancel).
109    pub fn set_cancelable(&mut self, cancelable: bool) {
110        unsafe {
111            sys::zwasm_config_set_cancellable(self.ptr, cancelable);
112        }
113    }
114}
115
116impl Drop for Config {
117    fn drop(&mut self) {
118        unsafe {
119            sys::zwasm_config_delete(self.ptr);
120        }
121    }
122}
123
124pub(crate) struct ConfigAllocator {
125    pub(crate) alloc: Box<dyn Fn(usize, usize) -> *mut std::ffi::c_void + Send + Sync + 'static>,
126    pub(crate) free: Box<dyn Fn(*mut std::ffi::c_void, usize, usize) + Send + Sync + 'static>,
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use crate::module;
133
134    /* ------------------------------------------------------------------ */
135    /* Wasm test modules (hand-coded binary)                              */
136    /* ------------------------------------------------------------------ */
137
138    /* (func (export "f") (result i32) (i32.const 42)) */
139    const RETURN42_WASM: &[u8] = &[
140        0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7f,
141        0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x06, 0x01, 0x04,
142        0x00, 0x41, 0x2a, 0x0b,
143    ];
144
145    #[test]
146    fn test_config_lifecycle() {
147        let config = Config::new().expect("Failed to create config");
148        let module = module::Module::new_configured(RETURN42_WASM, &config)
149            .expect("Failed to create module with config");
150        let results = module.invoke("f", &[]).expect("Failed to invoke function");
151        assert_eq!(results[0], 42, "f() == 42 via configured module");
152    }
153}