emlite/
lib.rs

1pub mod env;
2use crate::env::*;
3use std::ffi::CStr;
4
5#[repr(u32)]
6pub enum EmlitePredefHandles {
7    Null = 0,
8    Undefined,
9    False,
10    True,
11    GlobalThis,
12    Console,
13    Reserved,
14}
15
16/// Runs JS eval
17#[macro_export]
18macro_rules! eval {
19    ($src: literal) => {{
20        $crate::Val::global("eval").invoke(&[$crate::Val::from($src)])
21    }};
22    ($src: literal $(, $arg:expr)* $(,)?) => {{
23        $crate::Val::global("eval").invoke(
24            &[$crate::Val::from(&format!($src, $( $arg ),*)) ]
25        )
26    }};
27}
28
29/// A helper macro which packs values into a slice of Val
30#[macro_export]
31macro_rules! argv {
32    ($($rest:expr),*) => {{
33        [$($crate::Val::from($rest)),*]
34    }};
35}
36
37/// A wrapper around a javascript handle
38#[derive(Debug)]
39pub struct Val {
40    inner: Handle,
41}
42
43impl Val {
44    /// Returns the globalThis object
45    pub const fn global_this() -> Val {
46        Val { inner: EmlitePredefHandles::GlobalThis as _ }
47    }
48
49    /// Gets the property `prop`
50    pub fn get<T: Into<Val>>(&self, prop: T) -> Val {
51        let h = unsafe { emlite_val_get(self.as_handle(), prop.into().as_handle()) };
52        Val::take_ownership(h)
53    }
54
55    /// Gets a global object by `name`
56    pub fn global(name: &str) -> Val {
57        Val::global_this().get(name)
58    }
59
60    /// Gets a js null Val
61    pub const fn null() -> Val {
62        Val { inner: EmlitePredefHandles::Null as _ }
63    }
64
65    /// Gets a js undefined Val
66    pub const fn undefined() -> Val {
67        Val { inner: EmlitePredefHandles::Undefined as _ }
68    }
69
70    /// Gets a new js object
71    pub fn object() -> Val {
72        Val::take_ownership(unsafe { emlite_val_new_object() })
73    }
74
75    /// Gets a new js array
76    pub fn array() -> Val {
77        Val::take_ownership(unsafe { emlite_val_new_array() })
78    }
79
80    /// Set the underlying js object property `prop` to `val`
81    pub fn set<K: Into<Val>, V: Into<Val>>(&self, prop: K, val: V) {
82        unsafe {
83            emlite_val_set(
84                self.as_handle(),
85                prop.into().as_handle(),
86                val.into().as_handle(),
87            )
88        };
89    }
90
91    /// Checks whether a property `prop` exists
92    pub fn has<T: Into<Val>>(&self, prop: T) -> bool {
93        unsafe { emlite_val_has(self.as_handle(), prop.into().as_handle()) }
94    }
95
96    /// Checks whether a non-inherited property `prop` exists
97    pub fn has_own_property(&self, prop: &str) -> bool {
98        unsafe { emlite_val_obj_has_own_prop(self.as_handle(), prop.as_ptr() as _, prop.len()) }
99    }
100
101    /// Gets the typeof the underlying js object
102    pub fn type_of(&self) -> String {
103        unsafe {
104            let ptr = emlite_val_typeof(self.as_handle());
105            String::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).to_string()
106        }
107    }
108
109    /// Gets the element at index `idx`. Assumes the underlying js type is indexable
110    pub fn at<T: Into<Val>>(&self, idx: T) -> Val {
111        Val::take_ownership(unsafe { emlite_val_get(self.as_handle(), idx.into().as_handle()) })
112    }
113
114    /// Converts the underlying js array to a Vec of V
115    pub fn to_vec<V: FromVal>(&self) -> Vec<V> {
116        let len = self.get("length").as_::<usize>();
117        let mut v: Vec<V> = Vec::with_capacity(len);
118        for i in 0..len {
119            v.push(self.at::<i32>(i as _).as_::<V>());
120        }
121        v
122    }
123
124    /// Calls the method `f` with `args`, can return an undefined js value
125    pub fn call(&self, f: &str, args: &[Val]) -> Val {
126        unsafe {
127            let arr = Val::take_ownership(emlite_val_new_array());
128            for arg in args {
129                emlite_val_push(arr.as_handle(), arg.as_handle());
130            }
131            Val::take_ownership(emlite_val_obj_call(
132                self.as_handle(),
133                f.as_ptr() as _,
134                f.len(),
135                arr.as_handle(),
136            ))
137        }
138    }
139
140    /// Calls the object's constructor with `args` constructing a new object
141    pub fn new(&self, args: &[Val]) -> Val {
142        unsafe {
143            let arr = Val::take_ownership(emlite_val_new_array());
144            for arg in args {
145                emlite_val_push(arr.as_handle(), arg.as_handle());
146            }
147            Val::take_ownership(emlite_val_construct_new(self.as_handle(), arr.as_handle()))
148        }
149    }
150
151    /// Invokes the function object with `args`, can return an undefined js value
152    pub fn invoke(&self, args: &[Val]) -> Val {
153        unsafe {
154            let arr = Val::take_ownership(emlite_val_new_array());
155            for arg in args {
156                emlite_val_push(arr.as_handle(), arg.as_handle());
157            }
158            Val::take_ownership(emlite_val_func_call(self.as_handle(), arr.as_handle()))
159        }
160    }
161
162    /// Creates js function from a function pointer and returns its handle wrapped in a Val object
163    pub fn make_fn_raw(f: fn(Handle, Handle) -> Handle, data: Handle) -> Val {
164        let idx: u32 = f as usize as u32;
165        unsafe { Val::take_ownership(emlite_val_make_callback(idx, data)) }
166    }
167
168    /// Creates a js function from a Rust closure and returns a Val
169    pub fn make_fn<F: FnMut(&[Val]) -> Val>(cb: F) -> Val {
170        fn shim(args: Handle, data: Handle) -> Handle {
171            let v = Val::take_ownership(args);
172            let vals: Vec<Val> = v.to_vec();
173            let func0 = Val::take_ownership(data);
174            let a = func0.as_::<i32>() as usize as *mut Box<dyn FnMut(&[Val]) -> Val>;
175            let f: &mut (dyn FnMut(&[Val]) -> Val) = unsafe { &mut **a };
176            std::mem::forget(func0);
177            f(&vals).as_handle()
178        }
179        #[allow(clippy::type_complexity)]
180        let a: *mut Box<dyn FnMut(&[Val]) -> Val> = Box::into_raw(Box::new(Box::new(cb)));
181        let data = Val::from(a as Handle);
182        unsafe {
183            emlite_val_inc_ref(data.as_handle());
184        }
185        Self::make_fn_raw(shim, data.as_handle())
186    }
187
188    /// Awaits the invoked function object
189    pub fn await_(&self) -> Val {
190        eval!(
191            r#"
192            (async () => {{
193                let obj = EMLITE_VALMAP.toValue({});
194                let ret = await obj;
195                return EMLITE_VALMAP.toHandle(ret);
196            }})()
197        "#,
198            self.as_handle()
199        )
200    }
201
202    /// Decrements the refcount of the underlying handle
203    pub fn delete(v: Val) {
204        unsafe {
205            emlite_val_dec_ref(v.as_handle());
206        }
207    }
208
209    /// Throws a js object represented by Val
210    pub fn throw(v: Val) {
211        unsafe {
212            emlite_val_throw(v.as_handle());
213        }
214    }
215
216    /// Checks whether this Val is an instanceof `v`
217    pub fn instanceof(&self, v: Val) -> bool {
218        unsafe { emlite_val_instanceof(self.as_handle(), v.as_handle()) }
219    }
220
221    #[inline(always)]
222    pub fn as_<T>(&self) -> T
223    where
224        T: FromVal,
225    {
226        T::from_val(self)
227    }
228}
229
230impl From<bool> for Val {
231    fn from(v: bool) -> Self {
232        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
233    }
234}
235
236impl From<i8> for Val {
237    fn from(v: i8) -> Self {
238        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
239    }
240}
241
242impl From<u8> for Val {
243    fn from(v: u8) -> Self {
244        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
245    }
246}
247
248impl From<i16> for Val {
249    fn from(v: i16) -> Self {
250        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
251    }
252}
253
254impl From<u16> for Val {
255    fn from(v: u16) -> Self {
256        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
257    }
258}
259
260impl From<i32> for Val {
261    fn from(v: i32) -> Self {
262        Val::take_ownership(unsafe { emlite_val_make_int(v) })
263    }
264}
265
266impl From<u32> for Val {
267    fn from(v: u32) -> Self {
268        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
269    }
270}
271
272impl From<i64> for Val {
273    fn from(v: i64) -> Self {
274        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
275    }
276}
277
278impl From<u64> for Val {
279    fn from(v: u64) -> Self {
280        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
281    }
282}
283
284impl From<usize> for Val {
285    fn from(v: usize) -> Self {
286        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
287    }
288}
289
290impl From<isize> for Val {
291    fn from(v: isize) -> Self {
292        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
293    }
294}
295
296impl From<f32> for Val {
297    fn from(v: f32) -> Self {
298        Val::take_ownership(unsafe { emlite_val_make_double(v as _) })
299    }
300}
301
302impl From<f64> for Val {
303    fn from(v: f64) -> Self {
304        Val::take_ownership(unsafe { emlite_val_make_double(v) })
305    }
306}
307
308impl From<()> for Val {
309    fn from(_: ()) -> Self {
310        Val::undefined()
311    }
312}
313
314impl From<&str> for Val {
315    fn from(s: &str) -> Self {
316        Val::take_ownership(unsafe { emlite_val_make_str(s.as_ptr() as _, s.len()) })
317    }
318}
319
320impl From<String> for Val {
321    fn from(s: String) -> Self {
322        Val::take_ownership(unsafe { emlite_val_make_str(s.as_ptr() as _, s.len()) })
323    }
324}
325
326impl From<&String> for Val {
327    fn from(s: &String) -> Self {
328        Val::take_ownership(unsafe { emlite_val_make_str(s.as_ptr() as _, s.len()) })
329    }
330}
331
332impl Drop for Val {
333    fn drop(&mut self) {
334        unsafe { emlite_val_dec_ref(self.as_handle()) }
335    }
336}
337
338impl Clone for Val {
339    fn clone(&self) -> Val {
340        unsafe {
341            emlite_val_inc_ref(self.as_handle());
342        }
343        Val::take_ownership(self.as_handle())
344    }
345}
346
347use std::ops::{Deref, DerefMut};
348
349/// A console wrapper
350#[derive(Clone, Debug)]
351pub struct Console {
352    val: Val,
353}
354
355impl Console {
356    /// Gets the console
357    pub const fn get() -> Console {
358        Console {
359            val: Val {
360                inner: EmlitePredefHandles::Console as _,
361            },
362        }
363    }
364
365    /// Logs into the console
366    pub fn log(&self, args: &[Val]) {
367        self.val.call("log", args);
368    }
369
370    /// console.warn
371    pub fn warn(&self, args: &[Val]) {
372        self.val.call("warn", args);
373    }
374
375    /// console.info
376    pub fn info(&self, args: &[Val]) {
377        self.val.call("info", args);
378    }
379
380    /// Returns the underlying handle of the console
381    pub fn as_handle(&self) -> Handle {
382        self.val.as_handle()
383    }
384}
385
386impl Deref for Console {
387    type Target = Val;
388
389    fn deref(&self) -> &Self::Target {
390        &self.val
391    }
392}
393
394impl DerefMut for Console {
395    fn deref_mut(&mut self) -> &mut Self::Target {
396        &mut self.val
397    }
398}
399
400impl From<Console> for Val {
401    fn from(val: Console) -> Self {
402        Val::take_ownership(val.inner)
403    }
404}
405
406use std::cmp::Ordering;
407use std::ops::Not;
408
409impl PartialEq for Val {
410    fn eq(&self, other: &Val) -> bool {
411        unsafe { emlite_val_strictly_equals(self.as_handle(), other.as_handle()) }
412    }
413}
414
415impl PartialOrd for Val {
416    fn partial_cmp(&self, other: &Val) -> Option<Ordering> {
417        unsafe {
418            if emlite_val_strictly_equals(self.as_handle(), other.as_handle()) {
419                Some(Ordering::Equal)
420            } else if emlite_val_gt(self.as_handle(), other.as_handle()) {
421                Some(Ordering::Greater)
422            } else if emlite_val_lt(self.as_handle(), other.as_handle()) {
423                Some(Ordering::Less)
424            } else {
425                None
426            }
427        }
428    }
429}
430
431impl Not for Val {
432    type Output = bool;
433
434    fn not(self) -> Self::Output {
435        unsafe { emlite_val_not(self.as_handle()) }
436    }
437}
438
439pub trait FromVal: Sized {
440    /// Creates a Val object from another
441    fn from_val(v: &Val) -> Self;
442    /// Takes the ownership of a handle
443    fn take_ownership(v: Handle) -> Self;
444    /// Returns the raw js handle
445    fn as_handle(&self) -> Handle;
446}
447
448impl FromVal for Val {
449    fn from_val(v: &Val) -> Self {
450        unsafe {
451            emlite_val_inc_ref(v.inner);
452        }
453        Val {
454            inner: v.as_handle(),
455        }
456    }
457    fn take_ownership(v: Handle) -> Self {
458        Val { inner: v }
459    }
460    #[inline(always)]
461    fn as_handle(&self) -> Handle {
462        self.inner
463    }
464}
465
466impl FromVal for bool {
467    fn from_val(v: &Val) -> Self {
468        v.as_handle() > EmlitePredefHandles::False as u32
469    }
470    fn take_ownership(v: Handle) -> Self {
471        Self::from_val(&Val::take_ownership(v))
472    }
473    fn as_handle(&self) -> Handle {
474        EmlitePredefHandles::False as u32
475    }
476}
477
478macro_rules! impl_int {
479    ($($t:ty),*) => {$(
480        impl FromVal for $t {
481            fn from_val(v: &Val) -> Self {
482                unsafe {
483                    emlite_val_get_value_int(v.as_handle()) as Self
484                }
485            }
486            fn take_ownership(v: Handle) -> Self {
487                unsafe { emlite_val_get_value_int(v) as Self }
488            }
489            fn as_handle(&self) -> Handle {
490                0
491            }
492        }
493    )*}
494}
495
496impl_int!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
497
498macro_rules! impl_float {
499    ($($t:ty),*) => {$(
500        impl FromVal for $t {
501            fn from_val(v: &Val) -> Self {
502                unsafe { emlite_val_get_value_double(v.as_handle()) as Self }
503            }
504            fn take_ownership(v: Handle) -> Self {
505                unsafe { emlite_val_get_value_double(v) as Self }
506            }
507            fn as_handle(&self) -> Handle {
508                0
509            }
510        }
511    )*}
512}
513
514impl_float!(f32, f64);
515
516impl FromVal for String {
517    fn from_val(v: &Val) -> Self {
518        unsafe {
519            let ptr = emlite_val_get_value_string(v.as_handle());
520            CStr::from_ptr(ptr).to_string_lossy().into_owned()
521        }
522    }
523    fn take_ownership(v: Handle) -> Self {
524        unsafe {
525            let ptr = emlite_val_get_value_string(v);
526            CStr::from_ptr(ptr).to_string_lossy().into_owned()
527        }
528    }
529    fn as_handle(&self) -> Handle {
530        0
531    }
532}
533
534
535impl FromVal for &str {
536    fn from_val(v: &Val) -> Self {
537        unsafe {
538            let ptr = emlite_val_get_value_string(v.as_handle());
539            CStr::from_ptr(ptr).to_str().unwrap()
540        }
541    }
542    fn take_ownership(v: Handle) -> Self {
543        unsafe {
544            let ptr = emlite_val_get_value_string(v);
545            CStr::from_ptr(ptr).to_str().unwrap()
546        }
547    }
548    fn as_handle(&self) -> Handle {
549        0
550    }
551}