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
238impl Default for Features {
239    fn default() -> Self {
240        Self::new()
241    }
242}
243
244#[cfg(test)]
245mod test_features {
246    use super::*;
247    #[test]
248    fn default_features() {
249        let default = Features::default();
250        assert_eq!(
251            default,
252            Features {
253                threads: true,
254                reference_types: true,
255                simd: true,
256                bulk_memory: true,
257                multi_value: true,
258                tail_call: false,
259                module_linking: false,
260                multi_memory: false,
261                memory64: false,
262                exceptions: false,
263                relaxed_simd: false,
264                extended_const: false,
265            }
266        );
267    }
268
269    #[test]
270    fn enable_threads() {
271        let mut features = Features::new();
272        features.bulk_memory(false).threads(true);
273
274        assert!(features.threads);
275    }
276
277    #[test]
278    fn enable_reference_types() {
279        let mut features = Features::new();
280        features.bulk_memory(false).reference_types(true);
281        assert!(features.reference_types);
282        assert!(features.bulk_memory);
283    }
284
285    #[test]
286    fn enable_simd() {
287        let mut features = Features::new();
288        features.simd(true);
289        assert!(features.simd);
290    }
291
292    #[test]
293    fn enable_multi_value() {
294        let mut features = Features::new();
295        features.multi_value(true);
296        assert!(features.multi_value);
297    }
298
299    #[test]
300    fn enable_bulk_memory() {
301        let mut features = Features::new();
302        features.bulk_memory(true);
303        assert!(features.bulk_memory);
304    }
305
306    #[test]
307    fn disable_bulk_memory() {
308        let mut features = Features::new();
309        features
310            .threads(true)
311            .reference_types(true)
312            .bulk_memory(false);
313        assert!(!features.bulk_memory);
314        assert!(!features.reference_types);
315    }
316
317    #[test]
318    fn enable_tail_call() {
319        let mut features = Features::new();
320        features.tail_call(true);
321        assert!(features.tail_call);
322    }
323
324    #[test]
325    fn enable_module_linking() {
326        let mut features = Features::new();
327        features.module_linking(true);
328        assert!(features.module_linking);
329    }
330
331    #[test]
332    fn enable_multi_memory() {
333        let mut features = Features::new();
334        features.multi_memory(true);
335        assert!(features.multi_memory);
336    }
337
338    #[test]
339    fn enable_memory64() {
340        let mut features = Features::new();
341        features.memory64(true);
342        assert!(features.memory64);
343    }
344}