rquickjs_core/value/convert/
coerce.rs

1use crate::{convert::Coerced, qjs, Ctx, FromJs, Result, StdString, String, Value};
2use core::{
3    mem::MaybeUninit,
4    ops::{Deref, DerefMut},
5};
6
7impl<T> AsRef<T> for Coerced<T> {
8    fn as_ref(&self) -> &T {
9        &self.0
10    }
11}
12
13impl<T> AsMut<T> for Coerced<T> {
14    fn as_mut(&mut self) -> &mut T {
15        &mut self.0
16    }
17}
18
19impl<T> Deref for Coerced<T> {
20    type Target = T;
21
22    fn deref(&self) -> &Self::Target {
23        &self.0
24    }
25}
26
27impl<T> DerefMut for Coerced<T> {
28    fn deref_mut(&mut self) -> &mut Self::Target {
29        &mut self.0
30    }
31}
32
33/// Coerce a value to a string in the same way JavaScript would coerce values.
34impl<'js> FromJs<'js> for Coerced<String<'js>> {
35    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
36        Ok(Coerced(unsafe {
37            let result = qjs::JS_ToString(ctx.as_ptr(), value.as_js_value());
38            ctx.handle_exception(result)?;
39            // result should be a string now
40            // String itself will check for the tag when debug_assertions are enabled
41            // but is should always be string
42            String::from_js_value(ctx.clone(), result)
43        }))
44    }
45}
46
47/// Coerce a value to a string in the same way JavaScript would coerce values.
48impl<'js> FromJs<'js> for Coerced<StdString> {
49    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
50        <Coerced<String>>::from_js(ctx, value)
51            .and_then(|string| string.to_string())
52            .map(Coerced)
53    }
54}
55
56macro_rules! coerce_impls {
57	  ($($(#[$meta:meta])* $type:ident $func:ident,)*) => {
58		    $(
59            $(#[$meta])*
60            impl<'js> FromJs<'js> for Coerced<$type> {
61                fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
62                    let mut result = MaybeUninit::uninit();
63                    Ok(Coerced(unsafe {
64                        if 0 > qjs::$func(ctx.as_ptr(), result.as_mut_ptr(), value.as_js_value()) {
65                            return Err(ctx.raise_exception());
66                        }
67                        result.assume_init()
68                    }))
69                }
70            }
71        )*
72	  };
73}
74
75coerce_impls! {
76    /// Coerce a value to a `i32` in the same way JavaScript would coerce values
77    i32 JS_ToInt32,
78    /// Coerce a value to a `i64` in the same way JavaScript would coerce values
79    i64 JS_ToInt64Ext,
80    /// Coerce a value to a `u64` in the same way JavaScript would coerce values
81    u64 JS_ToIndex,
82    /// Coerce a value to a `f64` in the same way JavaScript would coerce values
83    f64 JS_ToFloat64,
84}
85
86/// Coerce a value to a `bool` in the same way JavaScript would coerce values
87impl<'js> FromJs<'js> for Coerced<bool> {
88    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
89        Ok(Coerced(unsafe {
90            let res = qjs::JS_ToBool(ctx.as_ptr(), value.as_js_value());
91            if 0 > res {
92                return Err(ctx.raise_exception());
93            }
94            res == 1
95        }))
96    }
97}