wasmer_types/
features.rs

1use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
2#[cfg(feature = "enable-serde")]
3use serde::{Deserialize, Serialize};
4
5/// Controls which experimental features will be enabled.
6/// Features usually have a corresponding [WebAssembly proposal].
7///
8/// [WebAssembly proposal]: https://github.com/WebAssembly/proposals
9#[derive(Clone, Debug, Eq, PartialEq)]
10#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
11#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
12#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
13#[rkyv(derive(Debug), compare(PartialEq))]
14pub struct Features {
15    /// Threads proposal should be enabled
16    pub threads: bool,
17    /// Reference Types proposal should be enabled
18    pub reference_types: bool,
19    /// SIMD proposal should be enabled
20    pub simd: bool,
21    /// Bulk Memory proposal should be enabled
22    pub bulk_memory: bool,
23    /// Multi Value proposal should be enabled
24    pub multi_value: bool,
25    /// Tail call proposal should be enabled
26    pub tail_call: bool,
27    /// Module Linking proposal should be enabled
28    pub module_linking: bool,
29    /// Multi Memory proposal should be enabled
30    pub multi_memory: bool,
31    /// 64-bit Memory proposal should be enabled
32    pub memory64: bool,
33    /// Wasm exceptions proposal should be enabled
34    pub exceptions: bool,
35    /// Relaxed SIMD proposal should be enabled
36    pub relaxed_simd: bool,
37    /// Extended constant expressions proposal should be enabled
38    pub extended_const: bool,
39}
40
41impl Features {
42    /// Create a new feature
43    pub fn new() -> Self {
44        Self {
45            threads: true,
46            // Reference types should be on by default
47            reference_types: true,
48            // SIMD should be on by default
49            simd: true,
50            // Bulk Memory should be on by default
51            bulk_memory: true,
52            // Multivalue should be on by default
53            multi_value: true,
54            tail_call: false,
55            module_linking: false,
56            multi_memory: false,
57            memory64: false,
58            exceptions: false,
59            relaxed_simd: false,
60            extended_const: false,
61        }
62    }
63
64    /// Configures whether the WebAssembly threads proposal will be enabled.
65    ///
66    /// The [WebAssembly threads proposal][threads] is not currently fully
67    /// standardized and is undergoing development. Support for this feature can
68    /// be enabled through this method for appropriate WebAssembly modules.
69    ///
70    /// This feature gates items such as shared memories and atomic
71    /// instructions.
72    ///
73    /// This is `false` by default.
74    ///
75    /// [threads]: https://github.com/webassembly/threads
76    pub fn threads(&mut self, enable: bool) -> &mut Self {
77        self.threads = enable;
78        self
79    }
80
81    /// Configures whether the WebAssembly reference types proposal will be
82    /// enabled.
83    ///
84    /// The [WebAssembly reference types proposal][proposal] is now
85    /// fully standardized and enabled by default.
86    ///
87    /// This feature gates items such as the `externref` type and multiple tables
88    /// being in a module. Note that enabling the reference types feature will
89    /// also enable the bulk memory feature.
90    ///
91    /// This is `true` by default.
92    ///
93    /// [proposal]: https://github.com/webassembly/reference-types
94    pub fn reference_types(&mut self, enable: bool) -> &mut Self {
95        self.reference_types = enable;
96        // The reference types proposal depends on the bulk memory proposal
97        if enable {
98            self.bulk_memory(true);
99        }
100        self
101    }
102
103    /// Configures whether the WebAssembly SIMD proposal will be
104    /// enabled.
105    ///
106    /// The [WebAssembly SIMD proposal][proposal] is not currently
107    /// fully standardized and is undergoing development. Support for this
108    /// feature can be enabled through this method for appropriate WebAssembly
109    /// modules.
110    ///
111    /// This feature gates items such as the `v128` type and all of its
112    /// operators being in a module.
113    ///
114    /// This is `false` by default.
115    ///
116    /// [proposal]: https://github.com/webassembly/simd
117    pub fn simd(&mut self, enable: bool) -> &mut Self {
118        self.simd = enable;
119        self
120    }
121
122    /// Configures whether the WebAssembly bulk memory operations proposal will
123    /// be enabled.
124    ///
125    /// The [WebAssembly bulk memory operations proposal][proposal] is now
126    /// fully standardized and enabled by default.
127    ///
128    /// This feature gates items such as the `memory.copy` instruction, passive
129    /// data/table segments, etc, being in a module.
130    ///
131    /// This is `true` by default.
132    ///
133    /// [proposal]: https://github.com/webassembly/bulk-memory-operations
134    pub fn bulk_memory(&mut self, enable: bool) -> &mut Self {
135        self.bulk_memory = enable;
136        // In case is false, we disable both threads and reference types
137        // since they both depend on bulk memory
138        if !enable {
139            self.reference_types(false);
140        }
141        self
142    }
143
144    /// Configures whether the WebAssembly multi-value proposal will
145    /// be enabled.
146    ///
147    /// The [WebAssembly multi-value proposal][proposal] is now fully
148    /// standardized and enabled by default, except with the singlepass
149    /// compiler which does not support it.
150    ///
151    /// This feature gates functions and blocks returning multiple values in a
152    /// module, for example.
153    ///
154    /// This is `true` by default.
155    ///
156    /// [proposal]: https://github.com/webassembly/multi-value
157    pub fn multi_value(&mut self, enable: bool) -> &mut Self {
158        self.multi_value = enable;
159        self
160    }
161
162    /// Configures whether the WebAssembly tail-call proposal will
163    /// be enabled.
164    ///
165    /// The [WebAssembly tail-call proposal][proposal] is not
166    /// currently fully standardized and is undergoing development.
167    /// Support for this feature can be enabled through this method for
168    /// appropriate WebAssembly modules.
169    ///
170    /// This feature gates tail-call functions in WebAssembly.
171    ///
172    /// This is `false` by default.
173    ///
174    /// [proposal]: https://github.com/webassembly/tail-call
175    pub fn tail_call(&mut self, enable: bool) -> &mut Self {
176        self.tail_call = enable;
177        self
178    }
179
180    /// Configures whether the WebAssembly module linking proposal will
181    /// be enabled.
182    ///
183    /// The [WebAssembly module linking proposal][proposal] is not
184    /// currently fully standardized and is undergoing development.
185    /// Support for this feature can be enabled through this method for
186    /// appropriate WebAssembly modules.
187    ///
188    /// This feature allows WebAssembly modules to define, import and
189    /// export modules and instances.
190    ///
191    /// This is `false` by default.
192    ///
193    /// [proposal]: https://github.com/webassembly/module-linking
194    pub fn module_linking(&mut self, enable: bool) -> &mut Self {
195        self.module_linking = enable;
196        self
197    }
198
199    /// Configures whether the WebAssembly multi-memory proposal will
200    /// be enabled.
201    ///
202    /// The [WebAssembly multi-memory proposal][proposal] is not
203    /// currently fully standardized and is undergoing development.
204    /// Support for this feature can be enabled through this method for
205    /// appropriate WebAssembly modules.
206    ///
207    /// This feature adds the ability to use multiple memories within a
208    /// single Wasm module.
209    ///
210    /// This is `false` by default.
211    ///
212    /// [proposal]: https://github.com/WebAssembly/multi-memory
213    pub fn multi_memory(&mut self, enable: bool) -> &mut Self {
214        self.multi_memory = enable;
215        self
216    }
217
218    /// Configures whether the WebAssembly 64-bit memory proposal will
219    /// be enabled.
220    ///
221    /// The [WebAssembly 64-bit memory proposal][proposal] is not
222    /// currently fully standardized and is undergoing development.
223    /// Support for this feature can be enabled through this method for
224    /// appropriate WebAssembly modules.
225    ///
226    /// This feature gates support for linear memory of sizes larger than
227    /// 2^32 bits.
228    ///
229    /// This is `false` by default.
230    ///
231    /// [proposal]: https://github.com/WebAssembly/memory64
232    pub fn memory64(&mut self, enable: bool) -> &mut Self {
233        self.memory64 = enable;
234        self
235    }
236
237    /// Configures whether the WebAssembly exception-handling proposal will be enabled.
238    ///
239    /// The [WebAssembly exception-handling proposal][eh] is not currently fully
240    /// standardized and is undergoing development. Support for this feature can
241    /// be enabled through this method for appropriate WebAssembly modules.
242    ///
243    /// This is `false` by default.
244    ///
245    /// [eh]: https://github.com/webassembly/exception-handling
246    pub fn exceptions(&mut self, enable: bool) -> &mut Self {
247        self.exceptions = enable;
248        self
249    }
250}
251
252impl Default for Features {
253    fn default() -> Self {
254        Self::new()
255    }
256}
257
258#[cfg(test)]
259mod test_features {
260    use super::*;
261    #[test]
262    fn default_features() {
263        let default = Features::default();
264        assert_eq!(
265            default,
266            Features {
267                threads: true,
268                reference_types: true,
269                simd: true,
270                bulk_memory: true,
271                multi_value: true,
272                tail_call: false,
273                module_linking: false,
274                multi_memory: false,
275                memory64: false,
276                exceptions: false,
277                relaxed_simd: false,
278                extended_const: false,
279            }
280        );
281    }
282
283    #[test]
284    fn enable_threads() {
285        let mut features = Features::new();
286        features.bulk_memory(false).threads(true);
287
288        assert!(features.threads);
289    }
290
291    #[test]
292    fn enable_reference_types() {
293        let mut features = Features::new();
294        features.bulk_memory(false).reference_types(true);
295        assert!(features.reference_types);
296        assert!(features.bulk_memory);
297    }
298
299    #[test]
300    fn enable_simd() {
301        let mut features = Features::new();
302        features.simd(true);
303        assert!(features.simd);
304    }
305
306    #[test]
307    fn enable_multi_value() {
308        let mut features = Features::new();
309        features.multi_value(true);
310        assert!(features.multi_value);
311    }
312
313    #[test]
314    fn enable_bulk_memory() {
315        let mut features = Features::new();
316        features.bulk_memory(true);
317        assert!(features.bulk_memory);
318    }
319
320    #[test]
321    fn disable_bulk_memory() {
322        let mut features = Features::new();
323        features
324            .threads(true)
325            .reference_types(true)
326            .bulk_memory(false);
327        assert!(!features.bulk_memory);
328        assert!(!features.reference_types);
329    }
330
331    #[test]
332    fn enable_tail_call() {
333        let mut features = Features::new();
334        features.tail_call(true);
335        assert!(features.tail_call);
336    }
337
338    #[test]
339    fn enable_module_linking() {
340        let mut features = Features::new();
341        features.module_linking(true);
342        assert!(features.module_linking);
343    }
344
345    #[test]
346    fn enable_multi_memory() {
347        let mut features = Features::new();
348        features.multi_memory(true);
349        assert!(features.multi_memory);
350    }
351
352    #[test]
353    fn enable_memory64() {
354        let mut features = Features::new();
355        features.memory64(true);
356        assert!(features.memory64);
357    }
358}