emlite/
lib.rs

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