Skip to main content

ferrijs_std/utils/
primordials.rs

1use std::any::type_name;
2
3use rquickjs::{
4    atom::PredefinedAtom, function::Constructor, runtime::UserDataGuard, Ctx, Exception, Function,
5    JsLifetime, Object, Result,
6};
7
8use crate::utils::result::ResultExt;
9
10#[derive(JsLifetime)]
11pub struct BasePrimordials<'js> {
12    // Constructors
13    pub constructor_map: Constructor<'js>,
14    pub constructor_set: Constructor<'js>,
15    pub constructor_date: Constructor<'js>,
16    pub constructor_error: Constructor<'js>,
17    pub constructor_type_error: Constructor<'js>,
18    pub constructor_range_error: Constructor<'js>,
19    pub constructor_regexp: Constructor<'js>,
20    pub constructor_uint8array: Constructor<'js>,
21    pub constructor_array_buffer: Constructor<'js>,
22    pub constructor_proxy: Constructor<'js>,
23    pub constructor_object: Constructor<'js>,
24    pub constructor_bool: Constructor<'js>,
25    pub constructor_number: Constructor<'js>,
26    pub constructor_string: Constructor<'js>,
27
28    // Prototypes
29    pub prototype_object: Object<'js>,
30    pub prototype_date: Object<'js>,
31    pub prototype_regexp: Object<'js>,
32    pub prototype_set: Object<'js>,
33    pub prototype_map: Object<'js>,
34    pub prototype_error: Object<'js>,
35
36    // Functions
37    pub function_array_from: Function<'js>,
38    pub function_array_buffer_is_view: Function<'js>,
39    pub function_get_own_property_descriptor: Function<'js>,
40    pub function_reflect_own_keys: Function<'js>,
41    pub function_parse_int: Function<'js>,
42    pub function_parse_float: Function<'js>,
43    pub prototype_iterator: Object<'js>,
44}
45
46pub trait Primordial<'js>
47where
48    Self: Sized + JsLifetime<'js>,
49{
50    fn get<'a>(ctx: &'a Ctx<'js>) -> Result<UserDataGuard<'a, Self>> {
51        let userdata = ctx.userdata::<Self>().or_throw_msg(
52            ctx,
53            &[
54                "Userdata of ",
55                type_name::<Self>(),
56                " not initialized. Call init(&ctx) on this type.",
57            ]
58            .concat(),
59        )?;
60
61        Ok(userdata)
62    }
63
64    fn init<'a>(ctx: &'a Ctx<'js>) -> Result<()> {
65        if ctx.userdata::<Self>().is_none() {
66            let primoridals = Self::new(ctx)?;
67            let _ = ctx.store_userdata(primoridals);
68        }
69
70        Ok(())
71    }
72    fn new(ctx: &Ctx<'js>) -> Result<Self>;
73}
74
75impl<'js> Primordial<'js> for BasePrimordials<'js> {
76    fn new(ctx: &Ctx<'js>) -> Result<Self> {
77        let globals = ctx.globals();
78
79        let constructor_object: Constructor = globals.get(PredefinedAtom::Object)?;
80        let prototype_object: Object = constructor_object.get(PredefinedAtom::Prototype)?;
81
82        let constructor_proxy: Constructor = globals.get(PredefinedAtom::Proxy)?;
83
84        let function_get_own_property_descriptor: Function =
85            constructor_object.get(PredefinedAtom::GetOwnPropertyDescriptor)?;
86
87        let constructor_date: Constructor = globals.get(PredefinedAtom::Date)?;
88        let prototype_date: Object = constructor_date.get(PredefinedAtom::Prototype)?;
89
90        let constructor_map: Constructor = globals.get(PredefinedAtom::Map)?;
91        let prototype_map: Object = constructor_map.get(PredefinedAtom::Prototype)?;
92
93        let constructor_set: Constructor = globals.get(PredefinedAtom::Set)?;
94        let prototype_set: Object = constructor_set.get(PredefinedAtom::Prototype)?;
95
96        let constructor_regexp: Constructor = globals.get(PredefinedAtom::RegExp)?;
97        let prototype_regexp: Object = constructor_regexp.get(PredefinedAtom::Prototype)?;
98
99        let constructor_uint8array: Constructor = globals.get(PredefinedAtom::Uint8Array)?;
100        let constructor_arraybuffer: Constructor = globals.get(PredefinedAtom::ArrayBuffer)?;
101
102        let constructor_error: Constructor = globals.get(PredefinedAtom::Error)?;
103        let constructor_type_error: Constructor = ctx.globals().get(PredefinedAtom::TypeError)?;
104        let constructor_range_error: Constructor = ctx.globals().get(PredefinedAtom::RangeError)?;
105        let prototype_error: Object = constructor_error.get(PredefinedAtom::Prototype)?;
106
107        let constructor_array: Object = globals.get(PredefinedAtom::Array)?;
108        let function_array_from: Function = constructor_array.get(PredefinedAtom::From)?;
109
110        let constructor_array_buffer: Object = globals.get(PredefinedAtom::ArrayBuffer)?;
111        let function_array_buffer_is_view: Function = constructor_array_buffer.get("isView")?;
112
113        let constructor_bool: Constructor = globals.get(PredefinedAtom::Boolean)?;
114
115        let constructor_number: Constructor = globals.get(PredefinedAtom::Number)?;
116        let function_parse_float: Function = constructor_number.get("parseFloat")?;
117        let function_parse_int: Function = constructor_number.get("parseInt")?;
118
119        let constructor_string: Constructor = globals.get(PredefinedAtom::String)?;
120
121        let reflect: Object = globals.get("Reflect")?;
122        let function_reflect_own_keys: Function = reflect.get("ownKeys")?;
123
124        // Walk to %IteratorPrototype% via an array iterator.
125        let array = rquickjs::Array::new(ctx.clone())?;
126        let iter_fn: Function = array
127            .as_object()
128            .get(rquickjs::atom::PredefinedAtom::SymbolIterator)?;
129        let array_iter: Object = iter_fn.call((rquickjs::function::This(array),))?;
130        let prototype_iterator = array_iter
131            .get_prototype()
132            .and_then(|p| p.get_prototype())
133            .ok_or_else(|| Exception::throw_internal(ctx, "missing %IteratorPrototype%"))?;
134
135        Ok(Self {
136            constructor_map,
137            constructor_set,
138            constructor_date,
139            constructor_proxy,
140            constructor_error,
141            constructor_type_error,
142            constructor_range_error,
143            constructor_regexp,
144            constructor_uint8array,
145            constructor_array_buffer: constructor_arraybuffer,
146            constructor_object,
147            constructor_bool,
148            constructor_number,
149            constructor_string,
150            prototype_object,
151            prototype_date,
152            prototype_regexp,
153            prototype_set,
154            prototype_map,
155            prototype_error,
156            function_array_from,
157            function_array_buffer_is_view,
158            function_get_own_property_descriptor,
159            function_reflect_own_keys,
160            function_parse_float,
161            function_parse_int,
162            prototype_iterator,
163        })
164    }
165}