Files
simple-rust-tests/__enclave/virt_enclave/external/quickjs-rs/src/callback.rs
2020-11-07 16:12:21 +08:00

298 lines
7.9 KiB
Rust

use std::{convert::TryFrom, marker::PhantomData, panic::RefUnwindSafe};
use crate::value::{JsValue, ValueError};
pub trait IntoCallbackResult {
fn into_callback_res(self) -> Result<JsValue, String>;
}
impl<T: Into<JsValue>> IntoCallbackResult for T {
fn into_callback_res(self) -> Result<JsValue, String> {
Ok(self.into())
}
}
impl<T: Into<JsValue>, E: std::fmt::Display> IntoCallbackResult for Result<T, E> {
fn into_callback_res(self) -> Result<JsValue, String> {
match self {
Ok(v) => Ok(v.into()),
Err(e) => Err(e.to_string()),
}
}
}
/// The Callback trait is implemented for functions/closures that can be
/// used as callbacks in the JS runtime.
pub trait Callback<F>: RefUnwindSafe {
/// The number of JS arguments required.
fn argument_count(&self) -> usize;
/// Execute the callback.
///
/// Should return:
/// - Err(_) if the JS values could not be converted
/// - Ok(Err(_)) if an error ocurred while processing.
/// The given error will be raised as a JS exception.
/// - Ok(Ok(result)) when execution succeeded.
fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError>;
}
macro_rules! impl_callback {
(@call $len:literal $self:ident $args:ident ) => {
$self()
};
(@call $len:literal $self:ident $args:ident $( $arg:ident ),* ) => {
{
let mut iter = $args.into_iter();
$self(
$(
$arg::try_from(iter.next().unwrap())?,
)*
)
}
};
[ $( $len:literal : ( $( $arg:ident, )* ), )* ] => {
$(
impl<
$( $arg, )*
R,
F,
> Callback<PhantomData<(
$( &$arg, )*
&R,
&F,
)>> for F
where
$( $arg: TryFrom<JsValue, Error = ValueError>, )*
R: IntoCallbackResult,
F: Fn( $( $arg, )* ) -> R + Sized + RefUnwindSafe,
{
fn argument_count(&self) -> usize {
$len
}
fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError> {
if args.len() != $len {
return Ok(Err(format!(
"Invalid argument count: Expected {}, got {}",
self.argument_count(),
args.len()
)));
}
let res = impl_callback!(@call $len self args $($arg),* );
Ok(res.into_callback_res())
}
}
)*
};
}
impl_callback![
0: (),
1: (A1,),
2: (A1, A2,),
3: (A1, A2, A3,),
4: (A1, A2, A3, A4,),
5: (A1, A2, A3, A4, A5,),
];
/// A wrapper around Vec<JsValue>, used for vararg callbacks.
///
/// To create a callback with a variable number of arguments, a callback closure
/// must take a single `Arguments` argument.
pub struct Arguments(Vec<JsValue>);
impl Arguments {
/// Unpack the arguments into a Vec.
pub fn into_vec(self) -> Vec<JsValue> {
self.0
}
}
impl<F> Callback<PhantomData<(&Arguments, &F)>> for F
where
F: Fn(Arguments) + Sized + RefUnwindSafe,
{
fn argument_count(&self) -> usize {
0
}
fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError> {
(self)(Arguments(args));
Ok(Ok(JsValue::Null))
}
}
impl<F, R> Callback<PhantomData<(&Arguments, &F, &R)>> for F
where
R: IntoCallbackResult,
F: Fn(Arguments) -> R + Sized + RefUnwindSafe,
{
fn argument_count(&self) -> usize {
0
}
fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError> {
let res = (self)(Arguments(args));
Ok(res.into_callback_res())
}
}
// Implement Callback for Fn() -> R functions.
//impl<R, F> Callback<PhantomData<(&R, &F)>> for F
//where
//R: Into<JsValue>,
//F: Fn() -> R + Sized + RefUnwindSafe,
//{
//fn argument_count(&self) -> usize {
//0
//}
//fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError> {
//if !args.is_empty() {
//return Ok(Err(format!(
//"Invalid argument count: Expected 0, got {}",
//args.len()
//)));
//}
//let res = self().into();
//Ok(Ok(res))
//}
//}
// Implement Callback for Fn(A) -> R functions.
//impl<A1, R, F> Callback<PhantomData<(&A1, &R, &F)>> for F
//where
//A1: TryFrom<JsValue, Error = ValueError>,
//R: Into<JsValue>,
//F: Fn(A1) -> R + Sized + RefUnwindSafe,
//{
//fn argument_count(&self) -> usize {
//1
//}
//fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError> {
//if args.len() != 1 {
//return Ok(Err(format!(
//"Invalid argument count: Expected 1, got {}",
//args.len()
//)));
//}
//let arg_raw = args.into_iter().next().expect("Invalid argument count");
//let arg = A1::try_from(arg_raw)?;
//let res = self(arg).into();
//Ok(Ok(res))
//}
//}
//// Implement Callback for Fn(A1, A2) -> R functions.
//impl<A1, A2, R, F> Callback<PhantomData<(&A1, &A2, &R, &F)>> for F
//where
//A1: TryFrom<JsValue, Error = ValueError>,
//A2: TryFrom<JsValue, Error = ValueError>,
//R: Into<JsValue>,
//F: Fn(A1, A2) -> R + Sized + RefUnwindSafe,
//{
//fn argument_count(&self) -> usize {
//2
//}
//fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError> {
//if args.len() != 2 {
//return Ok(Err(format!(
//"Invalid argument count: Expected 2, got {}",
//args.len()
//)));
//}
//let mut iter = args.into_iter();
//let arg1_raw = iter.next().expect("Invalid argument count");
//let arg1 = A1::try_from(arg1_raw)?;
//let arg2_raw = iter.next().expect("Invalid argument count");
//let arg2 = A2::try_from(arg2_raw)?;
//let res = self(arg1, arg2).into();
//Ok(Ok(res))
//}
//}
// Implement Callback for Fn(A1, A2, A3) -> R functions.
//impl<A1, A2, A3, R, F> Callback<PhantomData<(&A1, &A2, &A3, &R, &F)>> for F
//where
//A1: TryFrom<JsValue, Error = ValueError>,
//A2: TryFrom<JsValue, Error = ValueError>,
//A3: TryFrom<JsValue, Error = ValueError>,
//R: Into<JsValue>,
//F: Fn(A1, A2, A3) -> R + Sized + RefUnwindSafe,
//{
//fn argument_count(&self) -> usize {
//3
//}
//fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError> {
//if args.len() != self.argument_count() {
//return Ok(Err(format!(
//"Invalid argument count: Expected 3, got {}",
//args.len()
//)));
//}
//let mut iter = args.into_iter();
//let arg1_raw = iter.next().expect("Invalid argument count");
//let arg1 = A1::try_from(arg1_raw)?;
//let arg2_raw = iter.next().expect("Invalid argument count");
//let arg2 = A2::try_from(arg2_raw)?;
//let arg3_raw = iter.next().expect("Invalid argument count");
//let arg3 = A3::try_from(arg3_raw)?;
//let res = self(arg1, arg2, arg3).into();
//Ok(Ok(res))
//}
//}
//// Implement Callback for Fn(A1, A2, A3, A4) -> R functions.
//impl<A1, A2, A3, A4, R, F> Callback<PhantomData<(&A1, &A2, &A3, &A4, &R, &F)>> for F
//where
//A1: TryFrom<JsValue, Error = ValueError>,
//A2: TryFrom<JsValue, Error = ValueError>,
//A3: TryFrom<JsValue, Error = ValueError>,
//A4: TryFrom<JsValue, Error = ValueError>,
//R: Into<JsValue>,
//F: Fn(A1, A2, A3) -> R + Sized + RefUnwindSafe,
//{
//fn argument_count(&self) -> usize {
//4
//}
//fn call(&self, args: Vec<JsValue>) -> Result<Result<JsValue, String>, ValueError> {
//if args.len() != self.argument_count() {
//return Ok(Err(format!(
//"Invalid argument count: Expected 3, got {}",
//args.len()
//)));
//}
//let mut iter = args.into_iter();
//let arg1_raw = iter.next().expect("Invalid argument count");
//let arg1 = A1::try_from(arg1_raw)?;
//let arg2_raw = iter.next().expect("Invalid argument count");
//let arg2 = A2::try_from(arg2_raw)?;
//let arg3_raw = iter.next().expect("Invalid argument count");
//let arg3 = A3::try_from(arg3_raw)?;
//let res = self(arg1, arg2, arg3).into();
//Ok(Ok(res))
//}
//}
// RESULT variants.