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