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}