emlite/
lib.rs

1#![no_std]
2#![allow(unused_unsafe)]
3#![allow(unused_imports)]
4extern crate alloc;
5
6pub mod common;
7
8#[cfg(not(all(target_os = "wasi", target_env = "p2")))]
9pub mod env;
10#[cfg(not(all(target_os = "wasi", target_env = "p2")))]
11use crate::env::*;
12
13#[cfg(all(target_os = "wasi", target_env = "p2"))]
14pub mod wasip2env;
15#[cfg(all(target_os = "wasi", target_env = "p2"))]
16use crate::wasip2env::*;
17
18use crate::common::Handle;
19use core::ffi::CStr;
20use alloc::string::String;
21use alloc::string::ToString;
22use alloc::boxed::Box;
23use alloc::vec::Vec;
24use alloc::format;
25
26#[repr(u32)]
27pub enum EmlitePredefHandles {
28    Null = 0,
29    Undefined,
30    False,
31    True,
32    GlobalThis,
33    Console,
34    Reserved,
35}
36
37/// Runs JS eval
38#[macro_export]
39macro_rules! eval {
40    ($src: literal) => {{
41        $crate::Val::global("eval").invoke(&[$crate::Val::from($src)])
42    }};
43    ($src: literal $(, $arg:expr)* $(,)?) => {{
44        $crate::Val::global("eval").invoke(
45            &[$crate::Val::from(&format!($src, $( $arg ),*)) ]
46        )
47    }};
48}
49
50/// A helper macro which packs values into a slice of Val
51#[macro_export]
52macro_rules! argv {
53    ($($rest:expr),*) => {{
54        [$($crate::Val::from($rest)),*]
55    }};
56}
57
58pub fn init() {
59    unsafe {
60        emlite_init_handle_table();
61    }
62}
63
64/// A wrapper around a javascript handle
65#[derive(Debug)]
66pub struct Val {
67    inner: Handle,
68}
69
70impl Val {
71    /// Returns the globalThis object
72    pub const fn global_this() -> Val {
73        Val { inner: EmlitePredefHandles::GlobalThis as _ }
74    }
75
76    /// Gets the property `prop`
77    pub fn get<T: Into<Val>>(&self, prop: T) -> Val {
78        let h = unsafe { emlite_val_get(self.as_handle(), prop.into().as_handle()) };
79        Val::take_ownership(h)
80    }
81
82    /// Gets a global object by `name`
83    pub fn global(name: &str) -> Val {
84        Val::global_this().get(name)
85    }
86
87    /// Gets a js null Val
88    pub const fn null() -> Val {
89        Val { inner: EmlitePredefHandles::Null as _ }
90    }
91
92    /// Gets a js undefined Val
93    pub const fn undefined() -> Val {
94        Val { inner: EmlitePredefHandles::Undefined as _ }
95    }
96
97    /// Gets a new js object
98    pub fn object() -> Val {
99        Val::take_ownership(unsafe { emlite_val_new_object() })
100    }
101
102    /// Gets a new js array
103    pub fn array() -> Val {
104        Val::take_ownership(unsafe { emlite_val_new_array() })
105    }
106
107    /// Set the underlying js object property `prop` to `val`
108    pub fn set<K: Into<Val>, V: Into<Val>>(&self, prop: K, val: V) {
109        unsafe {
110            emlite_val_set(
111                self.as_handle(),
112                prop.into().as_handle(),
113                val.into().as_handle(),
114            )
115        };
116    }
117
118    /// Checks whether a property `prop` exists
119    pub fn has<T: Into<Val>>(&self, prop: T) -> bool {
120        unsafe { emlite_val_has(self.as_handle(), prop.into().as_handle()) }
121    }
122
123    /// Checks whether a non-inherited property `prop` exists
124    pub fn has_own_property(&self, prop: &str) -> bool {
125        #[cfg(all(target_os = "wasi", target_env = "p2"))]
126        unsafe { emlite_val_obj_has_own_prop(self.as_handle(), prop) }
127        #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
128        unsafe { emlite_val_obj_has_own_prop(self.as_handle(), prop.as_ptr() as _, prop.len()) }
129    }
130
131    /// Gets the typeof the underlying js object
132    pub fn type_of(&self) -> String {
133        unsafe {
134            #[cfg(all(target_os = "wasi", target_env = "p2"))]
135            {
136                emlite_val_typeof(self.as_handle())
137            }
138            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
139            {
140                let ptr = emlite_val_typeof(self.as_handle());
141                if ptr.is_null() {
142                    String::from("undefined")
143                } else {
144                    String::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).to_string()
145                }
146            }
147        }
148    }
149
150    /// Gets the element at index `idx`. Assumes the underlying js type is indexable
151    pub fn at<T: Into<Val>>(&self, idx: T) -> Val {
152        Val::take_ownership(unsafe { emlite_val_get(self.as_handle(), idx.into().as_handle()) })
153    }
154
155    /// Converts the underlying js array to a Vec of V
156    pub fn to_vec<V: FromVal>(&self) -> Vec<V> {
157        let len = self.get("length").as_::<usize>();
158        let mut v: Vec<V> = Vec::with_capacity(len);
159        for i in 0..len {
160            v.push(self.at::<i32>(i as _).as_::<V>());
161        }
162        v
163    }
164
165    /// Calls the method `f` with `args`, can return an undefined js value
166    pub fn call(&self, f: &str, args: &[Val]) -> Val {
167        unsafe {
168            let arr = Val::take_ownership(emlite_val_new_array());
169            for arg in args {
170                emlite_val_push(arr.as_handle(), arg.as_handle());
171            }
172            #[cfg(all(target_os = "wasi", target_env = "p2"))]
173            {
174                Val::take_ownership(emlite_val_obj_call(
175                    self.as_handle(),
176                    f,
177                    arr.as_handle(),
178                ))
179            }
180            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
181            {
182                Val::take_ownership(emlite_val_obj_call(
183                    self.as_handle(),
184                    f.as_ptr() as _,
185                    f.len(),
186                    arr.as_handle(),
187                ))
188            }
189        }
190    }
191
192    /// Calls the object's constructor with `args` constructing a new object
193    pub fn new(&self, args: &[Val]) -> Val {
194        unsafe {
195            let arr = Val::take_ownership(emlite_val_new_array());
196            for arg in args {
197                emlite_val_push(arr.as_handle(), arg.as_handle());
198            }
199            Val::take_ownership(emlite_val_construct_new(self.as_handle(), arr.as_handle()))
200        }
201    }
202
203    /// Invokes the function object with `args`, can return an undefined js value
204    pub fn invoke(&self, args: &[Val]) -> Val {
205        unsafe {
206            let arr = Val::take_ownership(emlite_val_new_array());
207            for arg in args {
208                emlite_val_push(arr.as_handle(), arg.as_handle());
209            }
210            Val::take_ownership(emlite_val_func_call(self.as_handle(), arr.as_handle()))
211        }
212    }
213
214    /// Creates js function from a function pointer and returns its handle wrapped in a Val object
215    pub fn make_fn_raw(f: fn(Handle, Handle) -> Handle, data: Handle) -> Val {
216        let idx: u32 = f as usize as u32;
217        unsafe { Val::take_ownership(emlite_val_make_callback(idx, data)) }
218    }
219
220    /// Creates a js function from a Rust closure and returns a Val
221    pub fn make_fn<F: FnMut(&[Val]) -> Val>(cb: F) -> Val {
222        fn shim(args: Handle, data: Handle) -> Handle {
223            let v = Val::take_ownership(args);
224            let vals: Vec<Val> = v.to_vec();
225            let func0 = Val::take_ownership(data);
226            let a = func0.as_::<i32>() as usize as *mut Box<dyn FnMut(&[Val]) -> Val>;
227            let f: &mut (dyn FnMut(&[Val]) -> Val) = unsafe { &mut **a };
228            core::mem::forget(func0);
229            f(&vals).as_handle()
230        }
231        #[allow(clippy::type_complexity)]
232        let a: *mut Box<dyn FnMut(&[Val]) -> Val> = Box::into_raw(Box::new(Box::new(cb)));
233        let data = Val::from(a as Handle);
234        unsafe {
235            emlite_val_inc_ref(data.as_handle());
236        }
237        Self::make_fn_raw(shim, data.as_handle())
238    }
239
240    /// Awaits the invoked function object
241    pub fn await_(&self) -> Val {
242        eval!(
243            r#"
244            (async () => {{
245                let obj = EMLITE_VALMAP.toValue({});
246                let ret = await obj;
247                return EMLITE_VALMAP.toHandle(ret);
248            }})()
249        "#,
250            self.as_handle()
251        )
252    }
253
254    /// Decrements the refcount of the underlying handle
255    pub fn delete(v: Val) {
256        unsafe {
257            emlite_val_dec_ref(v.as_handle());
258        }
259    }
260
261    /// Throws a js object represented by Val
262    pub fn throw(v: Val) -> ! {
263        unsafe {
264            emlite_val_throw(v.as_handle());
265        }
266    }
267
268    /// Checks whether this Val is an instanceof `v`
269    pub fn instanceof(&self, v: Val) -> bool {
270        unsafe { emlite_val_instanceof(self.as_handle(), v.as_handle()) }
271    }
272
273    pub fn is_number(&self) -> bool {
274        unsafe { emlite_val_is_number(self.as_handle()) }
275    }
276
277    pub fn is_bool(&self) -> bool {
278        unsafe { emlite_val_is_bool(self.as_handle()) }
279    }
280    
281    pub fn is_string(&self) -> bool {
282        unsafe { emlite_val_is_string(self.as_handle()) }
283    }
284
285    pub fn is_null(&self) -> bool {
286        self.as_handle() == EmlitePredefHandles::Null as u32
287    }
288
289    pub fn is_undefined(&self) -> bool {
290        self.as_handle() == EmlitePredefHandles::Undefined as u32
291    }
292
293    pub fn is_error(&self) -> bool {
294        self.instanceof(Val::global("Error"))
295    }
296
297    pub fn is_function(&self) -> bool {
298        self.instanceof(Val::global("Function"))
299    }
300
301    #[inline(always)]
302    pub fn as_<T>(&self) -> T
303    where
304        T: FromVal,
305    {
306        T::from_val(self)
307    }
308
309    /// Creates a Val from UTF-16 data
310    pub fn from_utf16(utf16: &[u16]) -> Val {
311        Val::from(utf16)
312    }
313
314    /// Extracts UTF-16 data as Option<Vec<u16>>
315    pub fn to_utf16(&self) -> Option<Vec<u16>> {
316        self.as_::<Option<Vec<u16>>>()
317    }
318
319    /// Extracts UTF-16 data, returning error if null or if self is error
320    pub fn to_utf16_result(&self) -> Result<Vec<u16>, Val> {
321        self.as_::<Result<Vec<u16>, Val>>()
322    }
323
324    /// Converts UTF-16 Vec<u16> to String, if possible
325    pub fn utf16_to_string(utf16: &[u16]) -> Result<String, ()> {
326        // Simple conversion that works for basic cases
327        // For a full implementation, you'd want proper UTF-16 decoding
328        match String::from_utf16(utf16) {
329            Ok(s) => Ok(s),
330            Err(_) => Err(()),
331        }
332    }
333
334    /// Creates a Val from a String by first converting to UTF-16
335    pub fn from_string_via_utf16(s: &str) -> Val {
336        let utf16: Vec<u16> = s.encode_utf16().collect();
337        Val::from_utf16(&utf16)
338    }
339}
340
341impl From<bool> for Val {
342    fn from(v: bool) -> Self {
343        Val::take_ownership(unsafe { emlite_val_make_bool(v as _) })
344    }
345}
346
347impl From<i8> for Val {
348    fn from(v: i8) -> Self {
349        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
350    }
351}
352
353impl From<u8> for Val {
354    fn from(v: u8) -> Self {
355        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
356    }
357}
358
359impl From<i16> for Val {
360    fn from(v: i16) -> Self {
361        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
362    }
363}
364
365impl From<u16> for Val {
366    fn from(v: u16) -> Self {
367        Val::take_ownership(unsafe { emlite_val_make_int(v as _) })
368    }
369}
370
371impl From<i32> for Val {
372    fn from(v: i32) -> Self {
373        Val::take_ownership(unsafe { emlite_val_make_int(v) })
374    }
375}
376
377impl From<u32> for Val {
378    fn from(v: u32) -> Self {
379        Val::take_ownership(unsafe { emlite_val_make_uint(v as _) })
380    }
381}
382
383impl From<i64> for Val {
384    fn from(v: i64) -> Self {
385        Val::take_ownership(unsafe { emlite_val_make_bigint(v as _) })
386    }
387}
388
389impl From<u64> for Val {
390    fn from(v: u64) -> Self {
391        Val::take_ownership(unsafe { emlite_val_make_biguint(v as _) })
392    }
393}
394
395impl From<usize> for Val {
396    fn from(v: usize) -> Self {
397        Val::take_ownership(unsafe { emlite_val_make_biguint(v as _) })
398    }
399}
400
401impl From<isize> for Val {
402    fn from(v: isize) -> Self {
403        Val::take_ownership(unsafe { emlite_val_make_bigint(v as _) })
404    }
405}
406
407impl From<f32> for Val {
408    fn from(v: f32) -> Self {
409        Val::take_ownership(unsafe { emlite_val_make_double(v as _) })
410    }
411}
412
413impl From<f64> for Val {
414    fn from(v: f64) -> Self {
415        Val::take_ownership(unsafe { emlite_val_make_double(v) })
416    }
417}
418
419impl From<()> for Val {
420    fn from(_: ()) -> Self {
421        Val::undefined()
422    }
423}
424
425impl From<&str> for Val {
426    fn from(s: &str) -> Self {
427        #[cfg(all(target_os = "wasi", target_env = "p2"))]
428        {
429            Val::take_ownership(unsafe { emlite_val_make_str(s) })
430        }
431        #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
432        {
433            Val::take_ownership(unsafe { emlite_val_make_str(s.as_ptr() as _, s.len()) })
434        }
435    }
436}
437
438impl From<String> for Val {
439    fn from(s: String) -> Self {
440        #[cfg(all(target_os = "wasi", target_env = "p2"))]
441        {
442            Val::take_ownership(unsafe { emlite_val_make_str(&s) })
443        }
444        #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
445        {
446            Val::take_ownership(unsafe { emlite_val_make_str(s.as_ptr() as _, s.len()) })
447        }
448    }
449}
450
451impl From<&String> for Val {
452    fn from(s: &String) -> Self {
453        #[cfg(all(target_os = "wasi", target_env = "p2"))]
454        {
455            Val::take_ownership(unsafe { emlite_val_make_str(s) })
456        }
457        #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
458        {
459            Val::take_ownership(unsafe { emlite_val_make_str(s.as_ptr() as _, s.len()) })
460        }
461    }
462}
463
464impl From<&[u16]> for Val {
465    fn from(s: &[u16]) -> Self {
466        #[cfg(all(target_os = "wasi", target_env = "p2"))]
467        {
468            Val::take_ownership(unsafe { emlite_val_make_str_utf16(s) })
469        }
470        #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
471        {
472            Val::take_ownership(unsafe { emlite_val_make_str_utf16(s.as_ptr(), s.len()) })
473        }
474    }
475}
476
477impl From<Vec<u16>> for Val {
478    fn from(s: Vec<u16>) -> Self {
479        #[cfg(all(target_os = "wasi", target_env = "p2"))]
480        {
481            Val::take_ownership(unsafe { emlite_val_make_str_utf16(&s) })
482        }
483        #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
484        {
485            Val::take_ownership(unsafe { emlite_val_make_str_utf16(s.as_ptr(), s.len()) })
486        }
487    }
488}
489
490impl From<&Vec<u16>> for Val {
491    fn from(s: &Vec<u16>) -> Self {
492        #[cfg(all(target_os = "wasi", target_env = "p2"))]
493        {
494            Val::take_ownership(unsafe { emlite_val_make_str_utf16(s) })
495        }
496        #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
497        {
498            Val::take_ownership(unsafe { emlite_val_make_str_utf16(s.as_ptr(), s.len()) })
499        }
500    }
501}
502
503impl From<&Val> for Val {
504    fn from(v: &Val) -> Self {
505        v.clone()
506    }
507}
508
509impl Drop for Val {
510    fn drop(&mut self) {
511        unsafe { emlite_val_dec_ref(self.as_handle()) }
512    }
513}
514
515impl Clone for Val {
516    fn clone(&self) -> Val {
517        unsafe {
518            emlite_val_inc_ref(self.as_handle());
519        }
520        Val::take_ownership(self.as_handle())
521    }
522}
523
524use core::ops::{Deref, DerefMut};
525
526/// A console wrapper
527#[derive(Clone, Debug)]
528pub struct Console {
529    val: Val,
530}
531
532impl Console {
533    /// Gets the console
534    pub const fn get() -> Console {
535        Console {
536            val: Val {
537                inner: EmlitePredefHandles::Console as _,
538            },
539        }
540    }
541
542    /// Logs into the console
543    pub fn log(&self, args: &[Val]) {
544        self.val.call("log", args);
545    }
546
547    /// console.warn
548    pub fn warn(&self, args: &[Val]) {
549        self.val.call("warn", args);
550    }
551
552    /// console.info
553    pub fn info(&self, args: &[Val]) {
554        self.val.call("info", args);
555    }
556
557    /// Returns the underlying handle of the console
558    pub fn as_handle(&self) -> Handle {
559        self.val.as_handle()
560    }
561}
562
563impl Deref for Console {
564    type Target = Val;
565
566    fn deref(&self) -> &Self::Target {
567        &self.val
568    }
569}
570
571impl DerefMut for Console {
572    fn deref_mut(&mut self) -> &mut Self::Target {
573        &mut self.val
574    }
575}
576
577impl From<Console> for Val {
578    fn from(val: Console) -> Self {
579        Val::take_ownership(val.as_handle())
580    }
581}
582
583use core::cmp::Ordering;
584use core::ops::Not;
585
586impl PartialEq for Val {
587    fn eq(&self, other: &Val) -> bool {
588        unsafe { emlite_val_strictly_equals(self.as_handle(), other.as_handle()) }
589    }
590}
591
592impl PartialOrd for Val {
593    fn partial_cmp(&self, other: &Val) -> Option<Ordering> {
594        unsafe {
595            if emlite_val_strictly_equals(self.as_handle(), other.as_handle()) {
596                Some(Ordering::Equal)
597            } else if emlite_val_gt(self.as_handle(), other.as_handle()) {
598                Some(Ordering::Greater)
599            } else if emlite_val_lt(self.as_handle(), other.as_handle()) {
600                Some(Ordering::Less)
601            } else {
602                None
603            }
604        }
605    }
606}
607
608impl Not for Val {
609    type Output = bool;
610
611    fn not(self) -> Self::Output {
612        unsafe { emlite_val_not(self.as_handle()) }
613    }
614}
615
616impl AsRef<Val> for Val {
617    #[inline]
618    fn as_ref(&self) -> &Val { self }
619}
620
621impl AsMut<Val> for Val {
622    #[inline]
623    fn as_mut(&mut self) -> &mut Val { self }
624}
625
626pub trait FromVal: Sized {
627    /// Creates a Val object from another
628    fn from_val(v: &Val) -> Self;
629    /// Takes the ownership of a handle
630    fn take_ownership(v: Handle) -> Self;
631    /// Returns the raw js handle
632    fn as_handle(&self) -> Handle;
633}
634
635impl FromVal for Val {
636    fn from_val(v: &Val) -> Self {
637        unsafe {
638            emlite_val_inc_ref(v.inner);
639        }
640        Val {
641            inner: v.as_handle(),
642        }
643    }
644    fn take_ownership(v: Handle) -> Self {
645        Val { inner: v }
646    }
647    #[inline(always)]
648    fn as_handle(&self) -> Handle {
649        self.inner
650    }
651}
652
653impl FromVal for Result<Val, Val> {
654    fn from_val(v: &Val) -> Self {
655        unsafe {
656            emlite_val_inc_ref(v.inner);
657        }
658        if v.is_error() {
659            Err(v.clone())
660        } else {
661            Ok(v.clone())
662        }
663    }
664    fn take_ownership(v: Handle) -> Self {
665        let temp = Val::take_ownership(v);
666        if temp.is_error() {
667            Err(temp)
668        } else {
669            Ok(temp)
670        }
671    }
672    #[inline(always)]
673    fn as_handle(&self) -> Handle {
674        match self {
675            Ok(ok) => ok.as_handle(),
676            Err(e) => e.as_handle(),
677        }
678    }
679}
680
681impl FromVal for bool {
682    fn from_val(v: &Val) -> Self {
683        unsafe {
684            #[cfg(all(target_os = "wasi", target_env = "p2"))]
685            {
686                !crate::wasip2env::emlite_val_not(v.as_handle())
687            }
688            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
689            {
690                !crate::env::emlite_val_not(v.as_handle())
691            }
692        }
693    }
694    fn take_ownership(v: Handle) -> Self {
695        Self::from_val(&Val::take_ownership(v))
696    }
697    fn as_handle(&self) -> Handle {
698        if *self { EmlitePredefHandles::True as u32 } else { EmlitePredefHandles::False as u32 }
699    }
700}
701
702
703impl FromVal for Option<bool> {
704    fn from_val(v: &Val) -> Self {
705        unsafe {
706            if v.is_error() || v.is_null() || v.is_undefined() {
707                None
708            } else {
709                #[cfg(all(target_os = "wasi", target_env = "p2"))]
710                {
711                    Some(!crate::wasip2env::emlite_val_not(v.as_handle()))
712                }
713                #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
714                {
715                    Some(!crate::env::emlite_val_not(v.as_handle()))
716                }
717            }
718        }
719    }
720    fn take_ownership(v: Handle) -> Self {
721        let temp = Val::take_ownership(v);
722        if temp.is_error() || temp.is_null() || temp.is_undefined() {
723            None
724        } else {
725            #[cfg(all(target_os = "wasi", target_env = "p2"))]
726            unsafe { Some(!crate::wasip2env::emlite_val_not(v)) }
727            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
728            unsafe { Some(!crate::env::emlite_val_not(v)) }
729        }
730    }
731    fn as_handle(&self) -> Handle {
732        match self {
733            Some(ok) => if *ok { EmlitePredefHandles::True as u32 } else { EmlitePredefHandles::False as u32 },
734            None => EmlitePredefHandles::Undefined as u32,
735        }
736    }
737}
738
739impl FromVal for Result<bool, Val> {
740    fn from_val(v: &Val) -> Self {
741        unsafe {
742            if v.is_error() {
743                Err(v.clone())
744            } else {
745                #[cfg(all(target_os = "wasi", target_env = "p2"))]
746                {
747                    Ok(!crate::wasip2env::emlite_val_not(v.as_handle()))
748                }
749                #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
750                {
751                    Ok(!crate::env::emlite_val_not(v.as_handle()))
752                }
753            }
754        }
755    }
756    fn take_ownership(v: Handle) -> Self {
757        let temp = Val::take_ownership(v);
758        if temp.is_error() {
759            Err(temp)
760        } else {
761            #[cfg(all(target_os = "wasi", target_env = "p2"))]
762            unsafe { Ok(!crate::wasip2env::emlite_val_not(v)) }
763            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
764            unsafe { Ok(!crate::env::emlite_val_not(v)) }
765        }
766    }
767    fn as_handle(&self) -> Handle {
768        match self {
769            Ok(ok) => if *ok { EmlitePredefHandles::True as u32 } else { EmlitePredefHandles::False as u32 },
770            Err(e) => e.as_handle(),
771        }
772    }
773}
774
775macro_rules! impl_int {
776    ($($t:ty),*) => {$(
777        impl FromVal for $t {
778            fn from_val(v: &Val) -> Self {
779                unsafe {
780                    emlite_val_get_value_int(v.as_handle()) as Self
781                }
782            }
783            fn take_ownership(v: Handle) -> Self {
784                unsafe { emlite_val_get_value_int(v) as Self }
785            }
786            fn as_handle(&self) -> Handle {
787                0
788            }
789        }
790        impl FromVal for Option<$t> {
791            fn from_val(v: &Val) -> Self {
792                unsafe {
793                    if !v.is_number() {
794                        None
795                    } else {
796                        Some(emlite_val_get_value_int(v.as_handle()) as $t)
797                    }
798                }
799            }
800            fn take_ownership(v: Handle) -> Self {
801                let temp = Val::take_ownership(v);
802                if !temp.is_number() {
803                    None
804                } else {
805                    unsafe { Some(emlite_val_get_value_int(v) as $t) }
806                }
807            }
808            fn as_handle(&self) -> Handle {
809                0
810            }
811        }
812        impl FromVal for Result<$t, Val> {
813            fn from_val(v: &Val) -> Self {
814                unsafe {
815                    if v.is_error() {
816                        Err(v.clone())
817                    } else {
818                        Ok(emlite_val_get_value_int(v.as_handle()) as $t)
819                    }
820                }
821            }
822            fn take_ownership(v: Handle) -> Self {
823                let temp = Val::take_ownership(v);
824                if temp.is_error() {
825                    Err(temp)
826                } else {
827                    unsafe { Ok(emlite_val_get_value_int(v) as $t) }
828                }
829            }
830            fn as_handle(&self) -> Handle {
831                0
832            }
833        }
834    )*}
835}
836
837macro_rules! impl_uint {
838    ($($t:ty),*) => {$(
839        impl FromVal for $t {
840            fn from_val(v: &Val) -> Self {
841                unsafe {
842                    emlite_val_get_value_uint(v.as_handle()) as Self
843                }
844            }
845            fn take_ownership(v: Handle) -> Self {
846                unsafe { emlite_val_get_value_uint(v) as Self }
847            }
848            fn as_handle(&self) -> Handle {
849                0
850            }
851        }
852        impl FromVal for Option<$t> {
853            fn from_val(v: &Val) -> Self {
854                unsafe {
855                    if !v.is_number() {
856                        None
857                    } else {
858                        Some(emlite_val_get_value_uint(v.as_handle()) as $t)
859                    }
860                }
861            }
862            fn take_ownership(v: Handle) -> Self {
863                let temp = Val::take_ownership(v);
864                if !temp.is_number() {
865                    None
866                } else {
867                    unsafe { Some(emlite_val_get_value_uint(v) as $t) }
868                }
869            }
870            fn as_handle(&self) -> Handle {
871                0
872            }
873        }
874        impl FromVal for Result<$t, Val> {
875            fn from_val(v: &Val) -> Self {
876                unsafe {
877                    if v.is_error() {
878                        Err(v.clone())
879                    } else {
880                        Ok(emlite_val_get_value_uint(v.as_handle()) as $t)
881                    }
882                }
883            }
884            fn take_ownership(v: Handle) -> Self {
885                let temp = Val::take_ownership(v);
886                if temp.is_error() {
887                    Err(temp)
888                } else {
889                    unsafe { Ok(emlite_val_get_value_uint(v) as $t) }
890                }
891            }
892            fn as_handle(&self) -> Handle {
893                0
894            }
895        }
896    )*}
897}
898
899macro_rules! impl_bigint {
900    ($($t:ty),*) => {$(
901        impl FromVal for $t {
902            fn from_val(v: &Val) -> Self {
903                unsafe {
904                    emlite_val_get_value_bigint(v.as_handle()) as Self
905                }
906            }
907            fn take_ownership(v: Handle) -> Self {
908                unsafe { emlite_val_get_value_bigint(v) as Self }
909            }
910            fn as_handle(&self) -> Handle {
911                0
912            }
913        }
914        impl FromVal for Option<$t> {
915            fn from_val(v: &Val) -> Self {
916                unsafe {
917                    if !v.is_number() {
918                        None
919                    } else {
920                        Some(emlite_val_get_value_bigint(v.as_handle()) as $t)
921                    }
922                }
923            }
924            fn take_ownership(v: Handle) -> Self {
925                let temp = Val::take_ownership(v);
926                if !temp.is_number() {
927                    None
928                } else {
929                    unsafe { Some(emlite_val_get_value_bigint(v) as $t) }
930                }
931            }
932            fn as_handle(&self) -> Handle {
933                0
934            }
935        }
936        impl FromVal for Result<$t, Val> {
937            fn from_val(v: &Val) -> Self {
938                unsafe {
939                    if v.is_error() {
940                        Err(v.clone())
941                    } else {
942                        Ok(emlite_val_get_value_bigint(v.as_handle()) as $t)
943                    }
944                }
945            }
946            fn take_ownership(v: Handle) -> Self {
947                let temp = Val::take_ownership(v);
948                if temp.is_error() {
949                    Err(temp)
950                } else {
951                    unsafe { Ok(emlite_val_get_value_bigint(v) as $t) }
952                }
953            }
954            fn as_handle(&self) -> Handle {
955                0
956            }
957        }
958    )*}
959}
960
961macro_rules! impl_biguint {
962    ($($t:ty),*) => {$(
963        impl FromVal for $t {
964            fn from_val(v: &Val) -> Self {
965                unsafe {
966                    emlite_val_get_value_biguint(v.as_handle()) as Self
967                }
968            }
969            fn take_ownership(v: Handle) -> Self {
970                unsafe { emlite_val_get_value_biguint(v) as Self }
971            }
972            fn as_handle(&self) -> Handle {
973                0
974            }
975        }
976        impl FromVal for Option<$t> {
977            fn from_val(v: &Val) -> Self {
978                unsafe {
979                    if !v.is_number() {
980                        None
981                    } else {
982                        Some(emlite_val_get_value_biguint(v.as_handle()) as $t)
983                    }
984                }
985            }
986            fn take_ownership(v: Handle) -> Self {
987                let temp = Val::take_ownership(v);
988                if !temp.is_number() {
989                    None
990                } else {
991                    unsafe { Some(emlite_val_get_value_biguint(v) as $t) }
992                }
993            }
994            fn as_handle(&self) -> Handle {
995                0
996            }
997        }
998        impl FromVal for Result<$t, Val> {
999            fn from_val(v: &Val) -> Self {
1000                unsafe {
1001                    if v.is_error() {
1002                        Err(v.clone())
1003                    } else {
1004                        Ok(emlite_val_get_value_biguint(v.as_handle()) as $t)
1005                    }
1006                }
1007            }
1008            fn take_ownership(v: Handle) -> Self {
1009                let temp = Val::take_ownership(v);
1010                if temp.is_error() {
1011                    Err(temp)
1012                } else {
1013                    unsafe { Ok(emlite_val_get_value_biguint(v) as $t) }
1014                }
1015            }
1016            fn as_handle(&self) -> Handle {
1017                0
1018            }
1019        }
1020    )*}
1021}
1022
1023impl_int!(i8, i16, i32);
1024impl_uint!(u8, u16, u32);
1025impl_bigint!(i64, isize);
1026impl_biguint!(u64, usize);
1027
1028macro_rules! impl_float {
1029    ($($t:ty),*) => {$(
1030        impl FromVal for $t {
1031            fn from_val(v: &Val) -> Self {
1032                unsafe { emlite_val_get_value_double(v.as_handle()) as Self }
1033            }
1034            fn take_ownership(v: Handle) -> Self {
1035                unsafe { emlite_val_get_value_double(v) as Self }
1036            }
1037            fn as_handle(&self) -> Handle {
1038                0
1039            }
1040        }
1041        impl FromVal for Option<$t> {
1042            fn from_val(v: &Val) -> Self {
1043                unsafe {
1044                    if !v.is_number() {
1045                        None
1046                    } else {
1047                        Some(emlite_val_get_value_double(v.as_handle()) as $t)
1048                    }
1049                }
1050            }
1051            fn take_ownership(v: Handle) -> Self {
1052                let temp = Val::take_ownership(v);
1053                if !temp.is_number() {
1054                    None
1055                } else {
1056                    unsafe { Some(emlite_val_get_value_double(v) as $t) }
1057                }
1058            }
1059            fn as_handle(&self) -> Handle {
1060                0
1061            }
1062        }
1063        impl FromVal for Result<$t, Val> {
1064            fn from_val(v: &Val) -> Self {
1065                unsafe {
1066                    if v.is_error() {
1067                        Err(v.clone())
1068                    } else {
1069                        Ok(emlite_val_get_value_double(v.as_handle()) as $t)
1070                    }
1071                }
1072            }
1073            fn take_ownership(v: Handle) -> Self {
1074                let temp = Val::take_ownership(v);
1075                if temp.is_error() {
1076                    Err(temp)
1077                } else {
1078                    unsafe { Ok(emlite_val_get_value_double(v) as $t) }
1079                }
1080            }
1081            fn as_handle(&self) -> Handle {
1082                0
1083            }
1084        }
1085    )*}
1086}
1087
1088impl_float!(f32, f64);
1089
1090impl FromVal for () {
1091    fn from_val(_v: &Val) -> Self {
1092        // Unit type doesn't carry any data, so we just return ()
1093        ()
1094    }
1095    fn take_ownership(_v: Handle) -> Self {
1096        ()
1097    }
1098    fn as_handle(&self) -> Handle {
1099        EmlitePredefHandles::Undefined as u32
1100    }
1101}
1102
1103impl FromVal for Option<String> {
1104    fn from_val(v: &Val) -> Self {
1105        unsafe {
1106            if !v.is_string() {
1107                return None;
1108            }
1109            #[cfg(all(target_os = "wasi", target_env = "p2"))]
1110            {
1111                Some(emlite_val_get_value_string(v.as_handle()))
1112            }
1113            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
1114            {
1115                let ptr = emlite_val_get_value_string(v.as_handle());
1116                if ptr.is_null() {
1117                    None
1118                } else {
1119                    Some(CStr::from_ptr(ptr).to_string_lossy().into_owned())
1120                }
1121            }
1122        }
1123    }
1124    fn take_ownership(v: Handle) -> Self {
1125        unsafe {
1126            if !emlite_val_is_string(v) {
1127                return None;
1128            }
1129            #[cfg(all(target_os = "wasi", target_env = "p2"))]
1130            {
1131                Some(emlite_val_get_value_string(v))
1132            }
1133            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
1134            {
1135                let ptr = emlite_val_get_value_string(v);
1136                if ptr.is_null() {
1137                    None
1138                } else {
1139                    Some(CStr::from_ptr(ptr).to_string_lossy().into_owned())
1140                }
1141            }
1142        }
1143    }
1144    fn as_handle(&self) -> Handle {
1145        0
1146    }
1147}
1148
1149impl FromVal for Result<String, Val> {
1150    fn from_val(v: &Val) -> Self {
1151        unsafe {
1152            if v.is_error() {
1153                Err(v.clone())
1154            } else if !v.is_string() {
1155                Err(Val::global("Error").new(&["Expected string".into()]))
1156            } else {
1157                #[cfg(all(target_os = "wasi", target_env = "p2"))]
1158                {
1159                    Ok(emlite_val_get_value_string(v.as_handle()))
1160                }
1161                #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
1162                {
1163                    let ptr = emlite_val_get_value_string(v.as_handle());
1164                    if ptr.is_null() {
1165                        Err(Val::global("Error").new(&["Null string".into()]))
1166                    } else {
1167                        Ok(CStr::from_ptr(ptr).to_string_lossy().into_owned())
1168                    }
1169                }
1170            }
1171        }
1172    }
1173    fn take_ownership(v: Handle) -> Self {
1174        unsafe {
1175            let temp = Val::take_ownership(v);
1176            if temp.is_error() {
1177                Err(temp)
1178            } else if !temp.is_string() {
1179                Err(Val::global("Error").new(&["Expected string".into()]))
1180            } else {
1181                #[cfg(all(target_os = "wasi", target_env = "p2"))]
1182                {
1183                    Ok(emlite_val_get_value_string(v))
1184                }
1185                #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
1186                {
1187                    let ptr = emlite_val_get_value_string(v);
1188                    if ptr.is_null() {
1189                        Err(Val::global("Error").new(&["Null string".into()]))
1190                    } else {
1191                        Ok(CStr::from_ptr(ptr).to_string_lossy().into_owned())
1192                    }
1193                }
1194            }
1195        }
1196    }
1197    fn as_handle(&self) -> Handle {
1198        0
1199    }
1200}
1201
1202impl FromVal for Option<Vec<u16>> {
1203    fn from_val(v: &Val) -> Self {
1204        unsafe {
1205            #[cfg(all(target_os = "wasi", target_env = "p2"))]
1206            {
1207                Some(emlite_val_get_value_string_utf16(v.as_handle()))
1208            }
1209            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
1210            {
1211                let ptr = emlite_val_get_value_string_utf16(v.as_handle());
1212                if ptr.is_null() {
1213                    None
1214                } else {
1215                    // Find length by searching for null terminator
1216                    let mut len = 0;
1217                    let mut current = ptr;
1218                    while *current != 0 {
1219                        len += 1;
1220                        current = current.add(1);
1221                    }
1222                    // Convert to Vec<u16>
1223                    let slice = core::slice::from_raw_parts(ptr, len);
1224                    Some(slice.to_vec())
1225                }
1226            }
1227        }
1228    }
1229    fn take_ownership(v: Handle) -> Self {
1230        unsafe {
1231            #[cfg(all(target_os = "wasi", target_env = "p2"))]
1232            {
1233                Some(emlite_val_get_value_string_utf16(v))
1234            }
1235            #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
1236            {
1237                let ptr = emlite_val_get_value_string_utf16(v);
1238                if ptr.is_null() {
1239                    None
1240                } else {
1241                    // Find length by searching for null terminator
1242                    let mut len = 0;
1243                    let mut current = ptr;
1244                    while *current != 0 {
1245                        len += 1;
1246                        current = current.add(1);
1247                    }
1248                    // Convert to Vec<u16>
1249                    let slice = core::slice::from_raw_parts(ptr, len);
1250                    Some(slice.to_vec())
1251                }
1252            }
1253        }
1254    }
1255    fn as_handle(&self) -> Handle {
1256        0
1257    }
1258}
1259
1260impl FromVal for Result<Vec<u16>, Val> {
1261    fn from_val(v: &Val) -> Self {
1262        unsafe {
1263            if v.is_error() {
1264                Err(v.clone())
1265            } else {
1266                #[cfg(all(target_os = "wasi", target_env = "p2"))]
1267                {
1268                    Ok(emlite_val_get_value_string_utf16(v.as_handle()))
1269                }
1270                #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
1271                {
1272                    let ptr = emlite_val_get_value_string_utf16(v.as_handle());
1273                    if ptr.is_null() {
1274                        Err(Val::global("Error").new(&["Null UTF-16 string".into()]))
1275                    } else {
1276                        // Find length by searching for null terminator
1277                        let mut len = 0;
1278                        let mut current = ptr;
1279                        while *current != 0 {
1280                            len += 1;
1281                            current = current.add(1);
1282                        }
1283                        // Convert to Vec<u16>
1284                        let slice = core::slice::from_raw_parts(ptr, len);
1285                        Ok(slice.to_vec())
1286                    }
1287                }
1288            }
1289        }
1290    }
1291    fn take_ownership(v: Handle) -> Self {
1292        unsafe {
1293            let temp = Val::take_ownership(v);
1294            if temp.is_error() {
1295                Err(temp)
1296            } else {
1297                #[cfg(all(target_os = "wasi", target_env = "p2"))]
1298                {
1299                    Ok(emlite_val_get_value_string_utf16(v))
1300                }
1301                #[cfg(not(all(target_os = "wasi", target_env = "p2")))]
1302                {
1303                    let ptr = emlite_val_get_value_string_utf16(v);
1304                    if ptr.is_null() {
1305                        Err(Val::global("Error").new(&["Null UTF-16 string".into()]))
1306                    } else {
1307                        // Find length by searching for null terminator
1308                        let mut len = 0;
1309                        let mut current = ptr;
1310                        while *current != 0 {
1311                            len += 1;
1312                            current = current.add(1);
1313                        }
1314                        // Convert to Vec<u16>
1315                        let slice = core::slice::from_raw_parts(ptr, len);
1316                        Ok(slice.to_vec())
1317                    }
1318                }
1319            }
1320        }
1321    }
1322    fn as_handle(&self) -> Handle {
1323        0
1324    }
1325}
1326
1327/// A marker trait for types that can be constructed from JavaScript error values.
1328/// This allows Result<T, E> implementations where E: FromJsError.
1329pub trait FromJsError {
1330    fn from_js_error(val: &Val) -> Self;
1331}
1332
1333/// Implementation for Result<T, E> where T: FromVal and E: FromJsError.
1334/// This allows clean conversion using as_::<Result<T, E>>() for JavaScript error handling.
1335impl<T, E> FromVal for Result<T, E>
1336where
1337    T: FromVal,
1338    E: FromJsError,
1339{
1340    fn from_val(v: &Val) -> Self {
1341        if v.is_error() {
1342            Err(E::from_js_error(v))
1343        } else {
1344            Ok(T::from_val(v))
1345        }
1346    }
1347    fn take_ownership(handle: Handle) -> Self {
1348        let temp = Val::take_ownership(handle);
1349        if temp.is_error() {
1350            Err(E::from_js_error(&temp))
1351        } else {
1352            Ok(T::take_ownership(handle))
1353        }
1354    }
1355    fn as_handle(&self) -> Handle {
1356        match self {
1357            Ok(ok) => ok.as_handle(),
1358            Err(_) => 0, // Errors don't have meaningful handles in this context
1359        }
1360    }
1361}
1362