1use super::*;
4
5pub(crate) const B64_CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7pub(crate) fn bytes_to_base64(bytes: &[u8]) -> String {
9 let mut out = String::new();
10 for chunk in bytes.chunks(3) {
11 let b0 = chunk.first().copied().unwrap_or(0);
12 let b1 = chunk.get(1).copied().unwrap_or(0);
13 let b2 = chunk.get(2).copied().unwrap_or(0);
14 out.push(B64_CHARS[(b0 >> 2) as usize] as char);
15 out.push(B64_CHARS[(((b0 & 0x3) << 4) | (b1 >> 4)) as usize] as char);
16 out.push(if chunk.len() > 1 {
17 B64_CHARS[(((b1 & 0xf) << 2) | (b2 >> 6)) as usize] as char
18 } else {
19 '='
20 });
21 out.push(if chunk.len() > 2 {
22 B64_CHARS[(b2 & 0x3f) as usize] as char
23 } else {
24 '='
25 });
26 }
27 out
28}
29
30pub(crate) fn base64_to_bytes(s: &str) -> Vec<u8> {
33 let mut bits: u32 = 0;
34 let mut nbits = 0u32;
35 let mut out: Vec<u8> = Vec::new();
36 for c in s.bytes() {
37 let v = match c {
38 b'A'..=b'Z' => c - b'A',
39 b'a'..=b'z' => c - b'a' + 26,
40 b'0'..=b'9' => c - b'0' + 52,
41 b'+' | b'-' => 62, b'/' | b'_' => 63, _ => continue,
44 };
45 bits = (bits << 6) | v as u32;
46 nbits += 6;
47 if nbits >= 8 {
48 nbits -= 8;
49 out.push((bits >> nbits) as u8);
50 }
51 }
52 out
53}
54
55pub(crate) fn bytes_to_hex(bytes: &[u8]) -> String {
57 const HEX: &[u8; 16] = b"0123456789abcdef";
58 let mut out = String::with_capacity(bytes.len() * 2);
59 for &b in bytes {
60 out.push(HEX[(b >> 4) as usize] as char);
61 out.push(HEX[(b & 0xf) as usize] as char);
62 }
63 out
64}
65
66pub(crate) fn hex_to_bytes(s: &str) -> Option<Vec<u8>> {
68 let s = s.as_bytes();
69 if !s.len().is_multiple_of(2) {
70 return None;
71 }
72 fn nibble(c: u8) -> Option<u8> {
73 match c {
74 b'0'..=b'9' => Some(c - b'0'),
75 b'a'..=b'f' => Some(c - b'a' + 10),
76 b'A'..=b'F' => Some(c - b'A' + 10),
77 _ => None,
78 }
79 }
80 let mut out = Vec::with_capacity(s.len() / 2);
81 for pair in s.chunks(2) {
82 let hi = nibble(pair[0])?;
83 let lo = nibble(pair[1])?;
84 out.push((hi << 4) | lo);
85 }
86 Some(out)
87}
88
89pub(crate) fn btoa(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
90 let s = arg(a, 0).to_js_string();
91 Ok(Value::str(bytes_to_base64(s.as_bytes())))
92}
93pub(crate) fn atob(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
94 let s = arg(a, 0).to_js_string();
95 let out = base64_to_bytes(&s);
96 Ok(Value::str(
97 alloc::string::String::from_utf8_lossy(&out).into_owned(),
98 ))
99}
100
101pub(crate) fn ta_to_bytes(this: &Value) -> Vec<u8> {
103 if let Value::Object(o) = this {
104 if let ObjKind::Array(items) = &o.borrow().kind {
105 return items.iter().map(|v| v.to_number() as i64 as u8).collect();
106 }
107 }
108 Vec::new()
109}
110
111pub(crate) fn ta_to_base64(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
113 Ok(Value::str(bytes_to_base64(&ta_to_bytes(&this))))
114}
115
116pub(crate) fn ta_to_hex(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
118 Ok(Value::str(bytes_to_hex(&ta_to_bytes(&this))))
119}
120
121pub(crate) fn ta_from_base64(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
123 let s = arg(a, 0).to_js_string();
124 Ok(make_uint8array(it, base64_to_bytes(&s)))
125}
126
127pub(crate) fn ta_from_hex(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
129 let s = arg(a, 0).to_js_string();
130 match hex_to_bytes(&s) {
131 Some(bytes) => Ok(make_uint8array(it, bytes)),
132 None => {
133 let err = syntax_error_ctor(
134 it,
135 Value::Undefined,
136 &[Value::str("Uint8Array.fromHex: invalid hex string")],
137 )?;
138 Err(err)
139 }
140 }
141}
142
143pub(crate) fn ta_write_bytes_into(this: &Value, bytes: &[u8], consumed_len: usize) -> Value {
150 let mut written = 0usize;
151 if let Value::Object(o) = this {
152 let mut b = o.borrow_mut();
153 if let ObjKind::Array(items) = &mut b.kind {
154 let cap = items.len();
155 written = bytes.len().min(cap);
156 for (slot, byte) in items.iter_mut().zip(bytes.iter()).take(written) {
157 *slot = Value::Number(*byte as f64);
158 }
159 }
160 }
161 let read = if written < bytes.len() {
162 consumed_len * written / bytes.len().max(1)
164 } else {
165 consumed_len
166 };
167 let o = Obj::plain();
168 {
169 let mut ob = o.borrow_mut();
170 ob.props.insert("read".into(), Value::Number(read as f64));
171 ob.props.insert("written".into(), Value::Number(written as f64));
172 }
173 Value::Object(o)
174}
175
176pub(crate) fn ta_set_from_base64(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
178 let s = arg(a, 0).to_js_string();
179 let bytes = base64_to_bytes(&s);
180 Ok(ta_write_bytes_into(&this, &bytes, s.chars().count()))
181}
182
183pub(crate) fn ta_set_from_hex(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
185 let s = arg(a, 0).to_js_string();
186 match hex_to_bytes(&s) {
187 Some(bytes) => {
188 let len = s.chars().count();
189 Ok(ta_write_bytes_into(&this, &bytes, len))
190 }
191 None => {
192 let err = syntax_error_ctor(
193 it,
194 Value::Undefined,
195 &[Value::str("Uint8Array.setFromHex: invalid hex string")],
196 )?;
197 Err(err)
198 }
199 }
200}
201
202pub(crate) fn percent_decode(s: &str, plus_as_space: bool) -> String {
208 let bytes = s.as_bytes();
209 let mut out: Vec<u8> = Vec::with_capacity(bytes.len());
210 let mut i = 0;
211 while i < bytes.len() {
212 if bytes[i] == b'%' && i + 2 < bytes.len() {
213 let h1 = bytes[i + 1];
214 let h2 = bytes[i + 2];
215 if let (Some(n1), Some(n2)) = (char::from(h1).to_digit(16), char::from(h2).to_digit(16)) {
216 let byte = ((n1 << 4) | n2) as u8;
217 out.push(byte);
218 i += 3;
219 continue;
220 }
221 }
222 if plus_as_space && bytes[i] == b'+' {
223 out.push(b' ');
224 } else {
225 out.push(bytes[i]);
226 }
227 i += 1;
228 }
229 String::from_utf8(out).unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned())
230}
231
232pub(crate) fn percent_encode_component(s: &str) -> String {
234 let mut out = String::new();
235 for b in s.as_bytes() {
236 match *b {
237 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'!' | b'~' | b'*'
238 | b'\'' | b'(' | b')' => {
239 out.push(*b as char);
240 }
241 _ => out.push_str(&alloc::format!("%{:02X}", b)),
242 }
243 }
244 out
245}
246
247pub(crate) fn percent_encode_uri(s: &str) -> String {
250 let mut out = String::new();
251 for b in s.as_bytes() {
252 match *b {
253 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'!' | b'~' | b'*'
254 | b'\'' | b'(' | b')' | b';' | b'/' | b'?' | b':' | b'@' | b'&' | b'=' | b'+'
255 | b'$' | b',' | b'#' => {
256 out.push(*b as char);
257 }
258 _ => out.push_str(&alloc::format!("%{:02X}", b)),
259 }
260 }
261 out
262}
263
264pub(crate) fn js_encode_uri_component(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
265 Ok(Value::str(percent_encode_component(&arg(a, 0).to_js_string())))
266}
267pub(crate) fn js_decode_uri_component(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
268 Ok(Value::str(percent_decode(&arg(a, 0).to_js_string(), false)))
269}
270pub(crate) fn js_encode_uri(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
271 Ok(Value::str(percent_encode_uri(&arg(a, 0).to_js_string())))
272}
273pub(crate) fn js_decode_uri(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
274 Ok(Value::str(percent_decode(&arg(a, 0).to_js_string(), false)))
275}
276
277pub(crate) fn js_escape(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
283 let s = arg(a, 0).to_js_string();
284 let mut out = String::new();
285 for c in s.chars() {
286 let unreserved =
287 matches!(c, 'A'..='Z' | 'a'..='z' | '0'..='9' | '@' | '*' | '_' | '+' | '-' | '.' | '/');
288 if unreserved {
289 out.push(c);
290 } else {
291 let cp = c as u32;
292 if cp <= 0xFF {
293 out.push_str(&alloc::format!("%{:02X}", cp));
294 } else {
295 out.push_str(&alloc::format!("%u{:04X}", cp));
296 }
297 }
298 }
299 Ok(Value::str(out))
300}
301pub(crate) fn js_unescape(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
304 let s = arg(a, 0).to_js_string();
305 let chars: Vec<char> = s.chars().collect();
306 let mut out = String::new();
307 let mut i = 0;
308 while i < chars.len() {
309 if chars[i] == '%' && i + 6 <= chars.len() && chars[i + 1] == 'u' {
310 let hex: String = chars[i + 2..i + 6].iter().collect();
311 if let Some(ch) = u32::from_str_radix(&hex, 16).ok().and_then(char::from_u32) {
312 out.push(ch);
313 i += 6;
314 continue;
315 }
316 }
317 if chars[i] == '%' && i + 3 <= chars.len() {
318 let hex: String = chars[i + 1..i + 3].iter().collect();
319 if let Some(ch) = u32::from_str_radix(&hex, 16).ok().and_then(char::from_u32) {
320 out.push(ch);
321 i += 3;
322 continue;
323 }
324 }
325 out.push(chars[i]);
326 i += 1;
327 }
328 Ok(Value::str(out))
329}
330
331pub(crate) static PERF_TS: AtomicU64 = AtomicU64::new(0);
332pub fn next_perf_timestamp() -> f64 {
335 PERF_TS.fetch_add(1, Ordering::Relaxed) as f64
336}
337pub(crate) fn performance_now(_it: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
338 Ok(Value::Number(next_perf_timestamp()))
339}
340pub(crate) fn perf_entries(this: &Value) -> alloc::vec::Vec<Value> {
341 if let Value::Object(o) = this {
342 if let Some(Value::Object(arr)) = o.borrow().props.get("_entries") {
343 if let ObjKind::Array(items) = &arr.borrow().kind {
344 return items.clone();
345 }
346 }
347 }
348 alloc::vec::Vec::new()
349}
350pub(crate) fn perf_push_entry(this: &Value, entry: Value) {
351 if let Value::Object(o) = this {
352 let arr = o.borrow().props.get("_entries").cloned();
353 if let Some(Value::Object(a)) = arr {
354 if let ObjKind::Array(items) = &mut a.borrow_mut().kind {
355 items.push(entry);
356 }
357 }
358 }
359}
360pub(crate) fn make_perf_entry(name: &str, entry_type: &str, start_time: f64, duration: f64) -> Value {
361 let o = Obj::plain();
362 {
363 let mut b = o.borrow_mut();
364 b.props.insert("name".into(), Value::str(name));
365 b.props.insert("entryType".into(), Value::str(entry_type));
366 b.props.insert("startTime".into(), Value::Number(start_time));
367 b.props.insert("duration".into(), Value::Number(duration));
368 }
369 Value::Object(o)
370}
371pub(crate) fn perf_mark(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
374 let name = arg(a, 0).to_js_string();
375 let start = next_perf_timestamp();
376 let entry = make_perf_entry(&name, "mark", start, 0.0);
377 perf_push_entry(&this, entry.clone());
378 perf_notify_observers(it, &this, &entry);
379 Ok(entry)
380}
381pub(crate) fn perf_find_mark_time(this: &Value, name: &str) -> Option<f64> {
382 perf_entries(this).into_iter().rev().find_map(|e| {
383 if let Value::Object(o) = &e {
384 let b = o.borrow();
385 let is_mark = b.props.get("entryType").map(|v| v.to_js_string()) == Some(String::from("mark"));
386 let matches_name = b.props.get("name").map(|v| v.to_js_string()) == Some(String::from(name));
387 if is_mark && matches_name {
388 return b.props.get("startTime").map(|v| v.to_number());
389 }
390 }
391 None
392 })
393}
394pub(crate) fn perf_measure(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
398 let name = arg(a, 0).to_js_string();
399 let start_time = match arg(a, 1) {
400 Value::Undefined => 0.0,
401 v => perf_find_mark_time(&this, &v.to_js_string()).unwrap_or(0.0),
402 };
403 let end_time = match arg(a, 2) {
404 Value::Undefined => next_perf_timestamp(),
405 v => perf_find_mark_time(&this, &v.to_js_string()).unwrap_or_else(next_perf_timestamp),
406 };
407 let entry = make_perf_entry(&name, "measure", start_time, end_time - start_time);
408 perf_push_entry(&this, entry.clone());
409 perf_notify_observers(it, &this, &entry);
410 Ok(entry)
411}
412pub(crate) fn perf_notify_observers(it: &mut Interp, this: &Value, entry: &Value) {
417 let entry_type = if let Value::Object(o) = entry {
418 o.borrow().props.get("entryType").map(|v| v.to_js_string()).unwrap_or_default()
419 } else {
420 return;
421 };
422 let observers: Vec<Value> = if let Value::Object(o) = this {
423 match o.borrow().props.get("_observers") {
424 Some(Value::Object(arr)) => match &arr.borrow().kind {
425 ObjKind::Array(items) => items.clone(),
426 _ => Vec::new(),
427 },
428 _ => Vec::new(),
429 }
430 } else {
431 Vec::new()
432 };
433 for obs in observers {
434 let matches_type = if let Value::Object(o) = &obs {
435 match o.borrow().props.get("_entry_types") {
436 Some(Value::Object(arr)) => match &arr.borrow().kind {
437 ObjKind::Array(items) => items.iter().any(|t| t.to_js_string() == entry_type),
438 _ => false,
439 },
440 _ => false,
441 }
442 } else {
443 false
444 };
445 if !matches_type {
446 continue;
447 }
448 let callback = if let Value::Object(o) = &obs {
449 o.borrow().props.get("_callback").cloned()
450 } else {
451 None
452 };
453 if let Some(cb) = callback.and_then(callable_or_none) {
454 let list = Obj::plain();
455 {
456 let mut b = list.borrow_mut();
457 b.props
458 .insert("_entries".into(), Value::Object(Obj::array(alloc::vec![entry.clone()])));
459 b.props
460 .insert("getEntries".into(), nv("getEntries", perf_observer_list_get_entries));
461 }
462 it.call_listener(
463 &cb,
464 Value::Undefined,
465 &[Value::Object(list), obs.clone()],
466 "PerformanceObserver callback",
467 );
468 }
469 }
470}
471pub(crate) fn perf_observer_list_get_entries(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
472 if let Value::Object(o) = &this {
473 if let Some(v) = o.borrow().props.get("_entries").cloned() {
474 return Ok(v);
475 }
476 }
477 Ok(Value::Object(Obj::array(alloc::vec::Vec::new())))
478}
479pub(crate) fn performance_observer_ctor(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
481 let callback = arg(a, 0);
482 let o = Obj::plain();
483 {
484 let mut b = o.borrow_mut();
485 b.props.insert("_callback".into(), callback);
486 b.props
487 .insert("_entry_types".into(), Value::Object(Obj::array(alloc::vec::Vec::new())));
488 b.props.insert("observe".into(), nv("observe", performance_observer_observe));
489 b.props
490 .insert("disconnect".into(), nv("disconnect", performance_observer_disconnect));
491 b.props.insert(
492 "takeRecords".into(),
493 nv("takeRecords", |_: &mut Interp, _: Value, _: &[Value]| {
494 Ok(Value::Object(Obj::array(alloc::vec::Vec::new())))
495 }),
496 );
497 }
498 Ok(Value::Object(o))
499}
500pub(crate) fn performance_observer_observe(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
512 let opts = arg(a, 0);
513 let types: Vec<Value> = match obj_prop(&opts, "entryTypes") {
514 Some(Value::Object(arr)) => match &arr.borrow().kind {
515 ObjKind::Array(items) => items.clone(),
516 _ => Vec::new(),
517 },
518 _ => match obj_prop(&opts, "type") {
519 Some(t) => alloc::vec![t],
520 None => Vec::new(),
521 },
522 };
523 let buffered = obj_prop(&opts, "buffered").map(|v| v.truthy()).unwrap_or(false);
524 if let Value::Object(o) = &this {
525 o.borrow_mut()
526 .props
527 .insert("_entry_types".into(), Value::Object(Obj::array(types.clone())));
528 }
529 let performance = it.global.borrow().vars.get("performance").cloned();
530 if let Some(Value::Object(perf)) = &performance {
531 let arr = perf.borrow().props.get("_observers").cloned();
532 if let Some(Value::Object(a2)) = arr {
533 if let ObjKind::Array(items) = &mut a2.borrow_mut().kind {
534 let dup = items.iter().any(|v| match (v, &this) {
535 (Value::Object(x), Value::Object(y)) => Rc::ptr_eq(x, y),
536 _ => false,
537 });
538 if !dup {
539 items.push(this.clone());
540 }
541 }
542 }
543 }
544 if buffered {
545 if let Some(perf_val) = performance {
546 let want: Vec<String> = types.iter().map(|t| t.to_js_string()).collect();
547 let matching: Vec<Value> = perf_entries(&perf_val)
548 .into_iter()
549 .filter(|e| {
550 if let Value::Object(o) = e {
551 let et = o.borrow().props.get("entryType").map(|v| v.to_js_string()).unwrap_or_default();
552 want.iter().any(|w| w == &et)
553 } else {
554 false
555 }
556 })
557 .collect();
558 if !matching.is_empty() {
559 let callback = if let Value::Object(o) = &this {
560 o.borrow().props.get("_callback").cloned()
561 } else {
562 None
563 };
564 if let Some(cb) = callback.and_then(callable_or_none) {
565 let list = Obj::plain();
566 {
567 let mut b = list.borrow_mut();
568 b.props.insert("_entries".into(), Value::Object(Obj::array(matching)));
569 b.props
570 .insert("getEntries".into(), nv("getEntries", perf_observer_list_get_entries));
571 }
572 it.call_listener(
573 &cb,
574 Value::Undefined,
575 &[Value::Object(list), this.clone()],
576 "PerformanceObserver callback",
577 );
578 }
579 }
580 }
581 }
582 Ok(Value::Undefined)
583}
584pub(crate) fn performance_observer_disconnect(it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
586 let performance = it.global.borrow().vars.get("performance").cloned();
587 if let Some(Value::Object(perf)) = performance {
588 let arr = perf.borrow().props.get("_observers").cloned();
589 if let Some(Value::Object(a2)) = arr {
590 if let ObjKind::Array(items) = &mut a2.borrow_mut().kind {
591 items.retain(|v| match (v, &this) {
592 (Value::Object(x), Value::Object(y)) => !Rc::ptr_eq(x, y),
593 _ => true,
594 });
595 }
596 }
597 }
598 Ok(Value::Undefined)
599}
600pub(crate) fn perf_get_entries(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
601 Ok(Value::Object(Obj::array(perf_entries(&this))))
602}
603pub(crate) fn perf_get_entries_by_type(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
604 let t = arg(a, 0).to_js_string();
605 let items: alloc::vec::Vec<Value> = perf_entries(&this)
606 .into_iter()
607 .filter(|e| {
608 matches!(e, Value::Object(o) if o.borrow().props.get("entryType").map(|v| v.to_js_string()) == Some(t.clone()))
609 })
610 .collect();
611 Ok(Value::Object(Obj::array(items)))
612}
613pub(crate) fn perf_get_entries_by_name(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
614 let name = arg(a, 0).to_js_string();
615 let type_filter = match arg(a, 1) {
616 Value::Undefined => None,
617 v => Some(v.to_js_string()),
618 };
619 let items: alloc::vec::Vec<Value> = perf_entries(&this)
620 .into_iter()
621 .filter(|e| {
622 if let Value::Object(o) = e {
623 let b = o.borrow();
624 let name_matches = b.props.get("name").map(|v| v.to_js_string()) == Some(name.clone());
625 let type_matches = type_filter
626 .as_ref()
627 .map(|t| b.props.get("entryType").map(|v| v.to_js_string()) == Some(t.clone()))
628 .unwrap_or(true);
629 name_matches && type_matches
630 } else {
631 false
632 }
633 })
634 .collect();
635 Ok(Value::Object(Obj::array(items)))
636}
637pub(crate) fn perf_clear_by_type(this: &Value, entry_type: &str, name_filter: Value) {
638 if let Value::Object(o) = this {
639 let arr = o.borrow().props.get("_entries").cloned();
640 if let Some(Value::Object(a)) = arr {
641 let name_filter = match name_filter {
642 Value::Undefined => None,
643 v => Some(v.to_js_string()),
644 };
645 if let ObjKind::Array(items) = &mut a.borrow_mut().kind {
646 items.retain(|e| {
647 if let Value::Object(eo) = e {
648 let b = eo.borrow();
649 let is_type =
650 b.props.get("entryType").map(|v| v.to_js_string()) == Some(String::from(entry_type));
651 let name_ok = name_filter
652 .as_ref()
653 .map(|n| b.props.get("name").map(|v| v.to_js_string()) == Some(n.clone()))
654 .unwrap_or(true);
655 !(is_type && name_ok)
656 } else {
657 true
658 }
659 });
660 }
661 }
662 }
663}
664pub(crate) fn perf_clear_marks(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
665 perf_clear_by_type(&this, "mark", arg(a, 0));
666 Ok(Value::Undefined)
667}
668pub(crate) fn perf_clear_measures(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
669 perf_clear_by_type(&this, "measure", arg(a, 0));
670 Ok(Value::Undefined)
671}
672
673pub(crate) fn next_rand_u64() -> u64 {
675 let mut x = RNG_SEED.load(Ordering::Relaxed);
676 x ^= x >> 12;
677 x ^= x << 25;
678 x ^= x >> 27;
679 RNG_SEED.store(x, Ordering::Relaxed);
680 x.wrapping_mul(0x2545F4914F6CDD1D)
681}
682