#![allow(unused_braces)]
use super::{Extern, RuntimeError, RuntimeValue, Type};
use crate::Value;
use std::any::TypeId;
pub(crate) struct ErasedFunction<'data, 'func> {
#[allow(clippy::type_complexity)]
inner: Box<
dyn FnMut(&mut [RuntimeValue<'data>]) -> Result<RuntimeValue<'data>, RuntimeError> + 'func,
>,
}
impl<'data, 'func> ErasedFunction<'data, 'func> {
pub(crate) fn new<A, R, F: Function<'data, A, R> + 'func>(mut inner: F) -> Self {
Self {
inner: Box::new(move |arguments| inner.call(arguments)),
}
}
pub(crate) fn call(
&mut self,
arguments: &mut [RuntimeValue<'data>],
) -> Result<RuntimeValue<'data>, RuntimeError> {
(self.inner)(arguments)
}
}
pub trait Function<'a, A, R>: Send + Sync {
const ARGS: usize;
fn receiver_type_id_extern_type() -> Option<(TypeId, Option<Type>)>;
fn call(
&mut self,
arguments: &mut [RuntimeValue<'a>],
) -> Result<RuntimeValue<'a>, RuntimeError>;
}
pub trait ToRuntimeValue<'a>: Sized {
fn to_value(self) -> RuntimeValue<'a>;
}
pub trait FromRuntimeValue<'a>: Sized {
const TYPE: Option<Type> = None;
fn type_id() -> Option<TypeId>;
fn from_value(value: &mut RuntimeValue<'a>) -> Option<Self>;
}
impl<'a> ToRuntimeValue<'a> for RuntimeValue<'a> {
fn to_value(self) -> RuntimeValue<'a> {
self
}
}
impl<'a> FromRuntimeValue<'a> for RuntimeValue<'a> {
fn type_id() -> Option<TypeId> {
None
}
fn from_value(value: &mut RuntimeValue<'a>) -> Option<Self> {
Some(std::mem::take(value))
}
}
macro_rules! both_ways {
($v:ident, $t:path, $typeid:tt) => {
impl<'a> ToRuntimeValue<'a> for $t {
fn to_value(self) -> RuntimeValue<'a> {
RuntimeValue::$v(self)
}
}
impl<'a, 'b> FromRuntimeValue<'a> for $t {
fn type_id() -> Option<TypeId> {
$typeid
}
fn from_value(value: &mut RuntimeValue<'a>) -> Option<Self> {
if let RuntimeValue::$v(v) = std::mem::take(value) {
Some(v)
} else {
None
}
}
}
};
}
both_ways!(Value, Value, { Some(TypeId::of::<Value>()) });
both_ways!(Extern, Extern<'a>, None);
#[cfg(feature = "extern_value_type")]
pub struct ExternValue<T>(pub std::rc::Rc<T>);
pub struct ExternRef<'a, T>(pub &'a T);
pub struct ExternMut<'a, T>(pub &'a mut T);
#[cfg(feature = "method_call_expression")]
pub struct Receiver<'a, 'b, T>
where
'a: 'b,
{
borrow: &'b mut RuntimeValue<'a>,
_spooky: std::marker::PhantomData<&'b T>,
}
#[cfg(feature = "method_call_expression")]
impl<'a, 'b> std::ops::Deref for Receiver<'a, 'b, Value> {
type Target = Value;
fn deref(&self) -> &Self::Target {
match &*self.borrow {
RuntimeValue::Value(v) => v,
_ => unreachable!(),
}
}
}
#[cfg(feature = "method_call_expression")]
impl<'a, 'b> std::ops::DerefMut for Receiver<'a, 'b, Value> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self.borrow {
RuntimeValue::Value(v) => v,
_ => unreachable!(),
}
}
}
#[cfg(all(feature = "method_call_expression", feature = "extern_value_type"))]
impl<'a, 'b, T: 'static> std::ops::Deref for Receiver<'a, 'b, ExternValue<T>> {
type Target = T;
fn deref(&self) -> &Self::Target {
match &*self.borrow {
RuntimeValue::Extern(Extern::Value(v)) => (**v).downcast_ref().unwrap(),
_ => unreachable!(),
}
}
}
#[cfg(feature = "method_call_expression")]
impl<'b, 'a: 'b, 'c, T: 'static> std::ops::Deref for Receiver<'a, 'b, ExternRef<'c, T>> {
type Target = T;
fn deref(&self) -> &Self::Target {
match &*self.borrow {
RuntimeValue::Extern(Extern::Ref(v)) => (**v).downcast_ref().unwrap(),
_ => unreachable!(),
}
}
}
#[cfg(feature = "method_call_expression")]
impl<'b, 'a: 'b, 'c, T: 'static> std::ops::Deref for Receiver<'a, 'b, ExternMut<'c, T>> {
type Target = T;
fn deref(&self) -> &Self::Target {
match &*self.borrow {
RuntimeValue::Extern(Extern::Mut(v)) => (**v).downcast_ref().unwrap(),
_ => unreachable!(),
}
}
}
#[cfg(feature = "method_call_expression")]
impl<'b, 'a: 'b, 'c, T: 'static> std::ops::DerefMut for Receiver<'a, 'b, ExternMut<'c, T>> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self.borrow {
RuntimeValue::Extern(Extern::Mut(v)) => (**v).downcast_mut().unwrap(),
_ => unreachable!(),
}
}
}
#[cfg(feature = "extern_value_type")]
impl<'a, T: 'static> ToRuntimeValue<'a> for ExternValue<T> {
fn to_value(self) -> RuntimeValue<'a> {
RuntimeValue::Extern(Extern::Value(self.0))
}
}
#[cfg(feature = "extern_value_type")]
impl<'a, T: 'static> FromRuntimeValue<'a> for ExternValue<T> {
const TYPE: Option<Type> = Some(Type::ExternValue);
fn type_id() -> Option<TypeId> {
Some(TypeId::of::<T>())
}
fn from_value(value: &mut RuntimeValue<'a>) -> Option<Self> {
if let RuntimeValue::Extern(Extern::Value(value)) = std::mem::take(value) {
value.downcast().ok().map(ExternValue)
} else {
None
}
}
}
impl<'a, T: 'static> ToRuntimeValue<'a> for ExternRef<'a, T> {
fn to_value(self) -> RuntimeValue<'a> {
RuntimeValue::Extern(Extern::Ref(self.0))
}
}
impl<'a, T: 'static> FromRuntimeValue<'a> for ExternRef<'a, T> {
const TYPE: Option<Type> = Some(Type::ExternRef);
fn type_id() -> Option<TypeId> {
Some(TypeId::of::<T>())
}
fn from_value(value: &mut RuntimeValue<'a>) -> Option<Self> {
if let RuntimeValue::Extern(Extern::Ref(value)) = std::mem::take(value) {
value.downcast_ref().map(ExternRef)
} else {
None
}
}
}
impl<'a, T: 'static> ToRuntimeValue<'a> for ExternMut<'a, T> {
fn to_value(self) -> RuntimeValue<'a> {
RuntimeValue::Extern(Extern::Mut(self.0))
}
}
impl<'a, T: 'static> FromRuntimeValue<'a> for ExternMut<'a, T> {
const TYPE: Option<Type> = Some(Type::ExternMut);
fn type_id() -> Option<TypeId> {
Some(TypeId::of::<T>())
}
fn from_value(value: &mut RuntimeValue<'a>) -> Option<Self> {
if let RuntimeValue::Extern(Extern::Mut(value)) = std::mem::take(value) {
value.downcast_mut().map(ExternMut)
} else {
None
}
}
}
#[allow(unused)]
macro_rules! impl_convert_argument {
($v:ident, $t:ident) => {
impl<'a> ToRuntimeValue<'a> for $t {
fn to_value(self) -> RuntimeValue<'a> {
RuntimeValue::Value(Value::$v(self))
}
}
impl<'a, 'b> FromRuntimeValue<'a> for $t {
const TYPE: Option<Type> = Some(Type::$v);
fn type_id() -> Option<TypeId> {
Some(TypeId::of::<Value>())
}
fn from_value(value: &mut RuntimeValue<'a>) -> Option<Self> {
if let RuntimeValue::Value(Value::$v(v)) = std::mem::take(value) {
Some(v)
} else {
None
}
}
}
};
}
#[cfg(feature = "bool_type")]
impl_convert_argument!(Bool, bool);
#[cfg(feature = "i32_type")]
impl_convert_argument!(I32, i32);
#[cfg(feature = "f32_type")]
impl_convert_argument!(F32, f32);
#[cfg(feature = "string_type")]
impl_convert_argument!(String, String);
macro_rules! impl_function {
($($a: ident),*) => {
impl<'a, $($a,)* R, FUNC: FnMut($($a),*) -> Result<R, RuntimeError> + Send + Sync> Function<'a, ((), ($($a,)*)), R> for FUNC
where $($a: FromRuntimeValue<'a> + 'a,)*
R: ToRuntimeValue<'a> {
const ARGS: usize = 0 $(
+ {
let _ = std::mem::size_of::<$a>();
1
}
)*;
fn receiver_type_id_extern_type() -> Option<(TypeId, Option<Type>)> {
None
}
fn call(
&mut self,
mut _arguments: &mut [RuntimeValue<'a>],
) -> Result<RuntimeValue<'a>, RuntimeError> {
if _arguments.len() != Self::ARGS {
return Err(RuntimeError::WrongNumberOfArguments{expected: Self::ARGS as u16, actual: _arguments.len() as u16});
}
let mut _i = 0;
(self)($({
let (first, rest) = _arguments.split_at_mut(1);
_arguments = rest;
let arg = &mut first[0];
let type_of = arg.type_of();
<$a>::from_value(arg).ok_or(RuntimeError::InvalidArgument{
expected: $a::TYPE,
actual: type_of
})?
}),*).map(move |v| v.to_value())
}
}
};
}
#[cfg(feature = "method_call_expression")]
macro_rules! impl_method {
($($a: ident),*) => {
impl<'a, RECEIVER, $($a,)* R: 'a, FUNC: for<'b> FnMut(Receiver<'a, 'b, RECEIVER>, $($a),*) -> Result<R, RuntimeError> + Send + Sync> Function<'a, (RECEIVER, (), ($($a,)*)), R> for FUNC
where RECEIVER: FromRuntimeValue<'a> + 'a,
$($a: FromRuntimeValue<'a>,)*
R: ToRuntimeValue<'a> {
const ARGS: usize = 1 $(
+ {
let _ = std::mem::size_of::<$a>();
1
}
)*;
fn receiver_type_id_extern_type() -> Option<(TypeId, Option<Type>)> {
<RECEIVER>::type_id().map(|type_id| (type_id, RECEIVER::TYPE.filter(|t| {
match t {
Type::ExternRef | Type::ExternMut => true,
#[cfg(feature = "extern_value_type")]
Type::ExternValue => true,
_ => false,
}
})))
}
fn call(
&mut self,
mut _arguments: &mut [RuntimeValue<'a>],
) -> Result<RuntimeValue<'a>, RuntimeError> {
if _arguments.len() != Self::ARGS {
return Err(RuntimeError::WrongNumberOfArguments{expected: Self::ARGS as u16, actual: _arguments.len() as u16});
}
let mut _i = 0;
(self)(
{
let (first, rest) = _arguments.split_at_mut(1);
_arguments = rest;
let arg = &mut first[0];
Receiver{
borrow: arg,
_spooky: std::marker::PhantomData,
}
},
$({
let (first, rest) = _arguments.split_at_mut(1);
_arguments = rest;
let arg = &mut first[0];
let type_of = arg.type_of();
<$a>::from_value(arg).ok_or(RuntimeError::InvalidArgument{
expected: $a::TYPE,
actual: type_of
})?
}),*).map(move |v| v.to_value())
}
}
};
}
macro_rules! impl_function_and_method {
($($a: ident),*) => {
impl_function!($($a),*);
#[cfg(feature = "method_call_expression")]
impl_method!($($a),*);
}
}
impl_function_and_method!();
impl_function_and_method!(A);
impl_function_and_method!(A, B);
impl_function_and_method!(A, B, C);
impl_function_and_method!(A, B, C, D);
impl_function_and_method!(A, B, C, D, E);
impl_function_and_method!(A, B, C, D, E, F);
impl_function_and_method!(A, B, C, D, E, F, G);
impl_function_and_method!(A, B, C, D, E, F, G, H);
impl_function_and_method!(A, B, C, D, E, F, G, H, I);
impl_function_and_method!(A, B, C, D, E, F, G, H, I, J);