rquickjs_core/context/
builder.rs

1use std::{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 BigInt support
75        BigInt JS_AddIntrinsicBigInt,
76        /// Add Performance support
77        Performance JS_AddPerformance,
78        /// Add WeakRef support
79        WeakRef JS_AddIntrinsicWeakRef,
80    }
81
82    /// Add none intrinsics
83    pub type None = ();
84
85    /// Add all intrinsics
86    pub type All = (
87        Date,
88        Eval,
89        RegExpCompiler,
90        RegExp,
91        Json,
92        Proxy,
93        MapSet,
94        TypedArrays,
95        Promise,
96        BigInt,
97        Performance,
98        WeakRef,
99    );
100}
101
102intrinsic_impls! {
103    @tuple:
104    ,
105    A,
106    A B,
107    A B C,
108    A B C D,
109    A B C D E,
110    A B C D E F,
111    A B C D E F G,
112    A B C D E F G H,
113    A B C D E F G H I,
114    A B C D E F G H I J,
115    A B C D E F G H I J K,
116    A B C D E F G H I J K L,
117    A B C D E F G H I J K L M,
118    A B C D E F G H I J K L M N,
119    A B C D E F G H I J K L M N O,
120    A B C D E F G H I J K L M N O P,
121    A B C D E F G H I J K L M N O P R,
122}
123
124impl Default for ContextBuilder<()> {
125    fn default() -> Self {
126        ContextBuilder(PhantomData)
127    }
128}
129
130impl<I: Intrinsic> ContextBuilder<I> {
131    pub fn with<J: Intrinsic>(self) -> ContextBuilder<(I, J)> {
132        ContextBuilder(PhantomData)
133    }
134
135    pub fn build(self, runtime: &Runtime) -> Result<Context> {
136        Context::custom::<I>(runtime)
137    }
138
139    #[cfg(feature = "futures")]
140    pub async fn build_async(self, runtime: &AsyncRuntime) -> Result<AsyncContext> {
141        AsyncContext::custom::<I>(runtime).await
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn all_intrinsinces() {
151        let rt = crate::Runtime::new().unwrap();
152        let ctx = Context::builder()
153            .with::<intrinsic::All>()
154            .build(&rt)
155            .unwrap();
156        let result: usize = ctx.with(|ctx| ctx.eval("1+1")).unwrap();
157        assert_eq!(result, 2);
158    }
159}