1use std::{
2 fmt::Debug,
3 io::{self, Write},
4};
5
6use anyhow::{Result, bail};
7use bitflags::bitflags;
8
9bitflags! {
10 #[derive(Debug)]
12 pub(crate) struct JSIntrinsics: u32 {
13 const DATE = 1;
14 const EVAL = 1 << 1;
15 const REGEXP_COMPILER = 1 << 2;
16 const REGEXP = 1 << 3;
17 const JSON = 1 << 4;
18 const PROXY = 1 << 5;
19 const MAP_SET = 1 << 6;
20 const TYPED_ARRAY = 1 << 7;
21 const PROMISE = 1 << 8;
22 const BIG_INT = 1 << 9;
23 const OPERATORS = 1 << 12;
25 const BIGNUM_EXTENSION = 1 << 13;
26 const TEXT_ENCODING = 1 << 14;
27 const WEAK_REF = 1 << 16;
29 const PERFORMANCE = 1 << 17;
30 }
31}
32
33bitflags! {
34 #[derive(Debug)]
47 pub(crate) struct JavyIntrinsics: u32 {
48 const STREAM_IO = 1;
49 }
50}
51
52pub struct Config {
57 pub(crate) intrinsics: JSIntrinsics,
59 pub(crate) javy_intrinsics: JavyIntrinsics,
61 pub(crate) simd_json_builtins: bool,
67 pub(crate) gc_threshold: usize,
69 pub(crate) memory_limit: usize,
72 pub(crate) max_stack_size: usize,
75 pub(crate) log_stream: Box<dyn Write>,
77 pub(crate) err_stream: Box<dyn Write>,
79}
80
81impl Default for Config {
82 fn default() -> Self {
84 let mut intrinsics = JSIntrinsics::all();
85 intrinsics.set(JSIntrinsics::TEXT_ENCODING, false);
86 intrinsics.set(JSIntrinsics::WEAK_REF, false);
87 intrinsics.set(JSIntrinsics::PERFORMANCE, false);
88 Self {
89 intrinsics,
90 javy_intrinsics: JavyIntrinsics::empty(),
91 simd_json_builtins: false,
92 gc_threshold: usize::MAX,
93 memory_limit: usize::MAX,
94 max_stack_size: 256 * 1024, log_stream: Box::new(std::io::stdout()),
96 err_stream: Box::new(std::io::stderr()),
97 }
98 }
99}
100
101impl Config {
102 pub fn date(&mut self, enable: bool) -> &mut Self {
104 self.intrinsics.set(JSIntrinsics::DATE, enable);
105 self
106 }
107
108 pub fn eval(&mut self, enable: bool) -> &mut Self {
110 self.intrinsics.set(JSIntrinsics::EVAL, enable);
111 self
112 }
113
114 pub fn regexp_compiler(&mut self, enable: bool) -> &mut Self {
116 self.intrinsics.set(JSIntrinsics::REGEXP_COMPILER, enable);
117 self
118 }
119
120 pub fn regexp(&mut self, enable: bool) -> &mut Self {
122 self.intrinsics.set(JSIntrinsics::REGEXP, enable);
123 self
124 }
125
126 pub fn json(&mut self, enable: bool) -> &mut Self {
129 self.intrinsics.set(JSIntrinsics::JSON, enable);
130 self
131 }
132
133 pub fn proxy(&mut self, enable: bool) -> &mut Self {
136 self.intrinsics.set(JSIntrinsics::PROXY, enable);
137 self
138 }
139
140 pub fn map_set(&mut self, enable: bool) -> &mut Self {
142 self.intrinsics.set(JSIntrinsics::MAP_SET, enable);
143 self
144 }
145
146 pub fn promise(&mut self, enable: bool) -> &mut Self {
148 self.intrinsics.set(JSIntrinsics::PROMISE, enable);
149 self
150 }
151
152 pub fn big_int(&mut self, enable: bool) -> &mut Self {
154 self.intrinsics.set(JSIntrinsics::BIG_INT, enable);
155 self
156 }
157
158 pub fn operator_overloading(&mut self, enable: bool) -> &mut Self {
160 self.intrinsics.set(JSIntrinsics::OPERATORS, enable);
161 self
162 }
163
164 pub fn bignum_extension(&mut self, enable: bool) -> &mut Self {
166 self.intrinsics.set(JSIntrinsics::BIGNUM_EXTENSION, enable);
167 self
168 }
169
170 pub fn text_encoding(&mut self, enable: bool) -> &mut Self {
173 self.intrinsics.set(JSIntrinsics::TEXT_ENCODING, enable);
174 self
175 }
176
177 pub fn javy_stream_io(&mut self, enable: bool) -> &mut Self {
184 self.javy_intrinsics.set(JavyIntrinsics::STREAM_IO, enable);
185 self
186 }
187
188 pub fn redirect_stdout_to_stderr(&mut self, enable: bool) -> &mut Self {
191 self.log_stream = if enable {
192 Box::new(io::stderr())
193 } else {
194 Box::new(io::stdout())
195 };
196 self
197 }
198
199 #[cfg(feature = "json")]
206 pub fn simd_json_builtins(&mut self, enable: bool) -> &mut Self {
207 self.simd_json_builtins = enable;
208 self
209 }
210
211 pub fn gc_threshold(&mut self, bytes: usize) -> &mut Self {
214 self.gc_threshold = bytes;
215 self
216 }
217
218 pub fn memory_limit(&mut self, bytes: usize) -> &mut Self {
221 self.memory_limit = bytes;
222 self
223 }
224
225 pub fn max_stack_size(&mut self, bytes: usize) -> &mut Self {
228 self.max_stack_size = bytes;
229 self
230 }
231
232 pub fn log_stream(&mut self, stream: Box<dyn Write>) -> &mut Self {
234 self.log_stream = stream;
235 self
236 }
237
238 pub fn err_stream(&mut self, stream: Box<dyn Write>) -> &mut Self {
240 self.err_stream = stream;
241 self
242 }
243
244 pub fn weak_ref(&mut self, enable: bool) -> &mut Self {
246 self.intrinsics.set(JSIntrinsics::WEAK_REF, enable);
247 self
248 }
249
250 pub fn performance(&mut self, enable: bool) -> &mut Self {
252 self.intrinsics.set(JSIntrinsics::PERFORMANCE, enable);
253 self
254 }
255
256 pub(crate) fn validate(self) -> Result<Self> {
257 if self.simd_json_builtins && !self.intrinsics.contains(JSIntrinsics::JSON) {
258 bail!("JSON Intrinsic is required to override JSON.parse and JSON.stringify");
259 }
260
261 Ok(self)
262 }
263}
264
265#[cfg(test)]
266#[cfg(feature = "json")]
267mod tests {
268 use super::Config;
269
270 #[test]
271 fn err_config_validation() {
272 let mut config = Config::default();
273 config.simd_json_builtins(true);
274 config.json(false);
275
276 assert!(config.validate().is_err());
277 }
278
279 #[test]
280 fn ok_config_validation() {
281 let mut config = Config::default();
282 config.simd_json_builtins(true);
283
284 assert!(config.validate().is_ok());
285 }
286}