emlite/
lib.rs

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