use crate::{convert::Coerced, qjs, Ctx, FromJs, Result, StdString, String, Value};
use std::{
mem::MaybeUninit,
ops::{Deref, DerefMut},
};
impl<T> AsRef<T> for Coerced<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> AsMut<T> for Coerced<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T> Deref for Coerced<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Coerced<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'js> FromJs<'js> for Coerced<String<'js>> {
fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
Ok(Coerced(unsafe {
let result = qjs::JS_ToString(ctx.as_ptr(), value.as_js_value());
ctx.handle_exception(result)?;
String::from_js_value(ctx.clone(), result)
}))
}
}
impl<'js> FromJs<'js> for Coerced<StdString> {
fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
<Coerced<String>>::from_js(ctx, value)
.and_then(|string| string.to_string())
.map(Coerced)
}
}
macro_rules! coerce_impls {
($($(#[$meta:meta])* $type:ident $func:ident,)*) => {
$(
$(#[$meta])*
impl<'js> FromJs<'js> for Coerced<$type> {
fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
let mut result = MaybeUninit::uninit();
Ok(Coerced(unsafe {
if 0 > qjs::$func(ctx.as_ptr(), result.as_mut_ptr(), value.as_js_value()) {
return Err(ctx.raise_exception());
}
result.assume_init()
}))
}
}
)*
};
}
coerce_impls! {
i32 JS_ToInt32,
i64 JS_ToInt64Ext,
u64 JS_ToIndex,
f64 JS_ToFloat64,
}
impl<'js> FromJs<'js> for Coerced<bool> {
fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
Ok(Coerced(unsafe {
let res = qjs::JS_ToBool(ctx.as_ptr(), value.as_js_value());
if 0 > res {
return Err(ctx.raise_exception());
}
res == 1
}))
}
}