1use derivative::Derivative;
2use derive_more::{From, Into};
3use quanta::{Clock, Instant};
4use rquickjs::{class::Trace, Coerced, Ctx, Exception, JsLifetime, Result};
5
6pub use crate::cancellation::CancellationTokenWrapper;
7
8#[derive(Trace, Derivative, From, Into, JsLifetime)]
9#[derivative(Clone, Debug)]
10#[rquickjs::class(rename = "Performance")]
11pub struct Performance {
12 #[qjs(skip_trace)]
13 clock: Clock,
14 #[qjs(skip_trace)]
15 instant: Instant,
16}
17
18#[rquickjs::methods]
19impl Performance {
20 #[qjs(constructor)]
21 pub fn new() -> Result<Self> {
22 let clock = Clock::new();
23 let instant = clock.now();
24 Ok(Self { clock, instant })
25 }
26
27 pub fn now(self) -> u64 {
28 self.instant.elapsed().as_millis().try_into().unwrap()
29 }
30
31 #[qjs(get, enumerable, rename = "timeOrigin")]
32 pub fn time_origin(self) -> u64 {
33 self.clock.raw()
34 }
35}
36
37#[rquickjs::function()]
38pub fn btoa(value: Coerced<String>) -> Result<String> {
39 #[cfg(feature = "base64-simd")]
40 {
41 use base64_simd::STANDARD;
42 Ok(STANDARD.encode_to_string(value.as_bytes()))
43 }
44 #[cfg(feature = "base64")]
45 {
46 use base64::prelude::*;
47
48 Ok(BASE64_STANDARD.encode(value.as_bytes()))
49 }
50}
51
52#[rquickjs::function()]
53pub fn atob(ctx: Ctx<'_>, value: Coerced<String>) -> Result<String> {
54 #[cfg(feature = "base64-simd")]
55 {
56 use base64_simd::STANDARD;
57 match STANDARD.decode_to_vec(value.as_bytes()) {
58 Ok(decoded) => Ok(String::from_utf8(decoded)?),
59 Err(e) => Err(Exception::throw_internal(&ctx, &format!("{e}"))),
60 }
61 }
62 #[cfg(feature = "base64")]
63 {
64 use base64::prelude::*;
65 match BASE64_STANDARD.decode(value.as_bytes()) {
66 Ok(decoded) => Ok(String::from_utf8(decoded)?),
67 Err(e) => Err(Exception::throw_internal(&ctx, &format!("{e}"))),
68 }
69 }
70}
71
72#[rquickjs::function()]
73pub fn gc<'js>(ctx: Ctx<'js>) {
74 ctx.run_gc();
75}
76
77#[rquickjs::module(rename = "camelCase", rename_vars = "camelCase")]
78pub mod core {
79 use rquickjs::{
80 module::{Declarations, Exports},
81 Ctx, Result,
82 };
83
84 pub use crate::{cancellation::CancellationTokenWrapper, Performance};
85
86 #[qjs(declare)]
87 pub fn declare(declare: &Declarations) -> Result<()> {
88 declare
89 .declare("atob")?
90 .declare("btoa")?
91 .declare("performance")?
92 .declare("gc")?;
93 Ok(())
94 }
95
96 #[qjs(evaluate)]
97 pub fn evaluate<'js>(ctx: &Ctx<'js>, e: &Exports<'js>) -> Result<()> {
98 let performance = Performance::new()?;
99
100 e.export("atob", super::js_atob)?
101 .export("btoa", super::js_btoa)?
102 .export("performance", performance.clone())?
103 .export("gc", super::js_gc)?;
104
105 ctx.globals().set("atob", super::js_atob)?;
106 ctx.globals().set("btoa", super::js_btoa)?;
107 ctx.globals().set("performance", performance)?;
108 ctx.globals().set("gc", super::js_gc)?;
109 Ok(())
110 }
111}
112
113pub mod cancellation;