Skip to main content

rquickjs_core/context/
builder.rs

1use core::{marker::PhantomData, ptr::NonNull};
2
3#[cfg(feature = "futures")]
4use crate::{context::AsyncContext, runtime::AsyncRuntime};
5use crate::{qjs, util::Sealed, Context, Result, Runtime};
6
7/// The internal trait to add JS builtins
8pub trait Intrinsic: Sealed {
9    /// # Safety
10    /// Do not need implement it yourself instead you may use predefined intrinsics from [`intrinsic`] module.
11    unsafe fn add_intrinsic(ctx: NonNull<qjs::JSContext>);
12}
13
14/// Used for building a [`Context`](struct.Context.html) with a specific set of intrinsics
15pub struct ContextBuilder<I>(PhantomData<I>);
16
17macro_rules! intrinsic_impls {
18    (@builtin: $($(#[$meta:meta])* $name:ident $func:ident $(($($args:expr),*))*,)*) => {
19        $(
20            $(#[$meta])*
21            pub struct $name;
22            impl crate::util::Sealed for $name { }
23
24            impl Intrinsic for $name {
25                unsafe fn add_intrinsic(ctx: NonNull<qjs::JSContext>) {
26                    qjs::$func(ctx.as_ptr() $(, $($args),*)*);
27                }
28            }
29        )*
30    };
31
32    (@tuple: $($($name:ident)*,)*) => {
33        $(
34            impl<$($name,)*> crate::util::Sealed for ($($name,)*) { }
35
36            impl<$($name,)*> Intrinsic for ($($name,)*)
37            where
38                $($name: Intrinsic,)*
39            {
40                unsafe fn add_intrinsic(_ctx: NonNull<qjs::JSContext>) {
41                    $($name::add_intrinsic(_ctx);)*
42                }
43            }
44        )*
45    }
46}
47
48/// A marker types for intrinsic
49///
50/// You can select just you need only. If `lto = true` any unused code will be drop by link-time optimizer.
51pub mod intrinsic {
52    use super::{qjs, Intrinsic, NonNull};
53
54    intrinsic_impls! {
55        @builtin:
56        /// Add Date object support
57        Date JS_AddIntrinsicDate,
58        /// Add evaluation support
59        Eval JS_AddIntrinsicEval,
60        /// Add RegExp compiler
61        RegExpCompiler JS_AddIntrinsicRegExpCompiler,
62        /// Add RegExp object support
63        RegExp JS_AddIntrinsicRegExp,
64        /// Add JSON parse and stringify
65        Json JS_AddIntrinsicJSON,
66        /// Add Proxy object support
67        Proxy JS_AddIntrinsicProxy,
68        /// Add MapSet object support
69        MapSet JS_AddIntrinsicMapSet,
70        /// Add Typed Arrays support
71        TypedArrays JS_AddIntrinsicTypedArrays,
72        /// Add Promise object support
73        Promise JS_AddIntrinsicPromise,
74        /// Add Performance support
75        Performance JS_AddPerformance,
76        /// Add WeakRef support
77        WeakRef JS_AddIntrinsicWeakRef,
78    }
79
80    /// Add none intrinsics
81    pub type None = ();
82
83    /// Add all intrinsics
84    pub type All = (
85        Date,
86        Eval,
87        RegExpCompiler,
88        RegExp,
89        Json,
90        Proxy,
91        MapSet,
92        TypedArrays,
93        Promise,
94        Performance,
95        WeakRef,
96    );
97}
98
99intrinsic_impls! {
100    @tuple:
101    ,
102    A,
103    A B,
104    A B C,
105    A B C D,
106    A B C D E,
107    A B C D E F,
108    A B C D E F G,
109    A B C D E F G H,
110    A B C D E F G H I,
111    A B C D E F G H I J,
112    A B C D E F G H I J K,
113    A B C D E F G H I J K L,
114    A B C D E F G H I J K L M,
115    A B C D E F G H I J K L M N,
116    A B C D E F G H I J K L M N O,
117    A B C D E F G H I J K L M N O P,
118    A B C D E F G H I J K L M N O P R,
119}
120
121impl Default for ContextBuilder<()> {
122    fn default() -> Self {
123        ContextBuilder(PhantomData)
124    }
125}
126
127impl<I: Intrinsic> ContextBuilder<I> {
128    pub fn with<J: Intrinsic>(self) -> ContextBuilder<(I, J)> {
129        ContextBuilder(PhantomData)
130    }
131
132    pub fn build(self, runtime: &Runtime) -> Result<Context> {
133        Context::custom::<I>(runtime)
134    }
135
136    #[cfg(feature = "futures")]
137    pub async fn build_async(self, runtime: &AsyncRuntime) -> Result<AsyncContext> {
138        AsyncContext::custom::<I>(runtime).await
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use super::*;
145
146    #[test]
147    fn all_intrinsinces() {
148        let rt = crate::Runtime::new().unwrap();
149        let ctx = Context::builder()
150            .with::<intrinsic::All>()
151            .build(&rt)
152            .unwrap();
153        let result: usize = ctx.with(|ctx| ctx.eval("1+1")).unwrap();
154        assert_eq!(result, 2);
155    }
156}