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}