use super::{JSValue, JSValueImpl};
use crate::{JSContext, JSResult, RongJSError};
pub trait JSValueConversion:
JSValueImpl
+ for<'a> From<(&'a Self::Context, bool)>
+ for<'a> From<(&'a Self::Context, i32)>
+ for<'a> From<(&'a Self::Context, u32)>
+ for<'a> From<(&'a Self::Context, i64)>
+ for<'a> From<(&'a Self::Context, u64)>
+ for<'a> From<(&'a Self::Context, f64)>
+ for<'a> From<(&'a Self::Context, &'a str)>
+ TryInto<bool, Error = RongJSError>
+ TryInto<i32, Error = RongJSError>
+ TryInto<u32, Error = RongJSError>
+ TryInto<i64, Error = RongJSError>
+ TryInto<u64, Error = RongJSError>
+ TryInto<f64, Error = RongJSError>
+ TryInto<String, Error = RongJSError>
{
}
impl<T> JSValueConversion for T where
T: JSValueImpl
+ for<'a> From<(&'a T::Context, bool)>
+ for<'a> From<(&'a T::Context, i32)>
+ for<'a> From<(&'a T::Context, u32)>
+ for<'a> From<(&'a T::Context, i64)>
+ for<'a> From<(&'a T::Context, u64)>
+ for<'a> From<(&'a T::Context, f64)>
+ for<'a> From<(&'a T::Context, &'a str)>
+ TryInto<bool, Error = RongJSError>
+ TryInto<i32, Error = RongJSError>
+ TryInto<u32, Error = RongJSError>
+ TryInto<i64, Error = RongJSError>
+ TryInto<u64, Error = RongJSError>
+ TryInto<f64, Error = RongJSError>
+ TryInto<String, Error = RongJSError>
{
}
pub trait JSCompatible: Sized {}
impl JSCompatible for i32 {}
impl JSCompatible for u32 {}
impl JSCompatible for i64 {}
impl JSCompatible for u64 {}
impl JSCompatible for f64 {}
impl JSCompatible for bool {}
pub trait FromJSValue<V>: Sized
where
V: JSValueImpl,
{
fn from_js_value(ctx: &JSContext<V::Context>, value: JSValue<V>) -> JSResult<Self>;
}
impl<V, T> FromJSValue<V> for T
where
V: JSValueImpl,
V: TryInto<T, Error = RongJSError>,
T: JSCompatible,
{
fn from_js_value(_ctx: &JSContext<V::Context>, value: JSValue<V>) -> JSResult<Self> {
value.into_value().try_into()
}
}
impl<V> FromJSValue<V> for ()
where
V: JSValueImpl,
{
fn from_js_value(_ctx: &JSContext<V::Context>, _value: JSValue<V>) -> JSResult<Self> {
Ok(())
}
}
impl<V> FromJSValue<V> for String
where
V: JSValueImpl,
V: TryInto<String, Error = RongJSError>,
{
fn from_js_value(_ctx: &JSContext<V::Context>, value: JSValue<V>) -> JSResult<Self> {
value.into_value().try_into()
}
}
impl<V, T> FromJSValue<V> for Option<T>
where
V: JSValueImpl + super::JSTypeOf,
T: FromJSValue<V>,
{
fn from_js_value(ctx: &JSContext<V::Context>, value: JSValue<V>) -> JSResult<Self> {
if value.is_null() || value.is_undefined() {
Ok(None)
} else {
T::from_js_value(ctx, value).map(Some)
}
}
}
pub trait IntoJSValue<V>
where
V: JSValueImpl,
{
fn into_js_value(self, ctx: &JSContext<V::Context>) -> JSValue<V>;
}
impl<V> IntoJSValue<V> for &str
where
V: JSValueImpl,
V: for<'a> From<(&'a V::Context, &'a str)>,
{
fn into_js_value(self, ctx: &JSContext<V::Context>) -> JSValue<V> {
let raw = V::from((ctx.as_ref(), self));
JSValue::from_raw(ctx, raw)
}
}
impl<V> IntoJSValue<V> for String
where
V: JSValueImpl,
V: for<'a> From<(&'a V::Context, &'a str)>,
{
fn into_js_value(self, ctx: &JSContext<V::Context>) -> JSValue<V> {
let raw = V::from((ctx.as_ref(), self.as_str()));
JSValue::from_raw(ctx, raw)
}
}
impl<V> IntoJSValue<V> for ()
where
V: JSValueImpl,
{
fn into_js_value(self, ctx: &JSContext<V::Context>) -> JSValue<V> {
JSValue::from_raw(ctx, V::create_undefined(ctx.as_ref()))
}
}
impl<V, T> IntoJSValue<V> for T
where
V: JSValueImpl,
V: for<'a> From<(&'a V::Context, T)>,
T: JSCompatible,
{
fn into_js_value(self, ctx: &JSContext<V::Context>) -> JSValue<V> {
JSValue::from_raw(ctx, V::from((ctx.as_ref(), self)))
}
}
impl<V, T> IntoJSValue<V> for Option<T>
where
V: JSValueImpl,
T: IntoJSValue<V>,
{
fn into_js_value(self, ctx: &JSContext<V::Context>) -> JSValue<V> {
match self {
Some(value) => value.into_js_value(ctx),
None => JSValue::from_raw(ctx, V::create_null(ctx.as_ref())), }
}
}
macro_rules! impl_js_converter_for_int {
($($type:ty => $intermediate:ty),*) => {
$(
impl<V> FromJSValue<V> for $type
where
V: JSValueImpl,
V: TryInto<$intermediate, Error = RongJSError>,
{
fn from_js_value(_ctx: &JSContext<V::Context>, value: JSValue<V>) -> JSResult<Self> {
let intermediate = TryInto::<$intermediate>::try_into(value.into_value())?;
Ok(intermediate as $type)
}
}
impl<V> IntoJSValue<V> for $type
where
V: JSValueImpl,
V: for<'a> From<(&'a V::Context, $intermediate)>,
{
fn into_js_value(self, ctx: &JSContext<V::Context>) -> JSValue<V> {
JSValue::from_raw(ctx, V::from((ctx.as_ref(), self as $intermediate)))
}
}
)*
};
}
impl_js_converter_for_int! {
i8 => i32,
u8 => u32,
i16 => i32,
u16 => u32,
usize => u64,
isize => i64
}