pub use crate::ll::bytecode::{FunctionParameterCount, MethodParameterCount};
use crate::{
ll::{bytecode::Environment, gc::Memory, value::RawValue},
Error, IntoValue, LanguageErrorKind, RawForeignFunction, TryFromValue, Value,
};
fn create_rawff(
f: impl Fn(&Environment, &mut Memory, &[RawValue]) -> Result<RawValue, LanguageErrorKind> + 'static,
) -> RawForeignFunction {
Box::new(f)
}
#[derive(Debug)]
pub struct Arguments<'a> {
this: RawValue,
inner: &'a [RawValue],
env: &'a Environment,
}
impl<'a> Arguments<'a> {
pub fn new(raw_arguments: &'a [RawValue], env: &'a Environment) -> Self {
Self { this: raw_arguments[0], inner: &raw_arguments[1..], env }
}
pub fn count(&self) -> usize {
self.inner.len()
}
pub fn expect_exactly(&self, n: usize) -> Result<(), Error> {
if self.count() != n {
Err(Error::ArgumentCount { expected: n, got: self.count() })
} else {
Ok(())
}
}
pub fn expect_at_least(&self, n: usize) -> Result<(), Error> {
if self.count() < n {
Err(Error::ArgumentCount { expected: n, got: self.count() })
} else {
Ok(())
}
}
pub fn raw_self(&self) -> &RawValue {
&self.this
}
pub fn nth(&self, n: usize) -> Option<&RawValue> {
self.inner.get(n)
}
pub fn get<T>(&self, n: usize) -> Result<T, Error>
where
T: TryFromValue,
{
let value = self.inner.get(n).cloned().unwrap_or(RawValue::from(()));
T::try_from_value(&Value::from_raw(value), self.env).map_err(|error| {
if let Error::TypeMismatch { expected, got } = error {
Error::ArgumentTypeMismatch { index: n, expected, got }
} else {
error
}
})
}
pub fn array(&self) -> &[RawValue] {
self.inner
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct RawSelf<'a>(pub(crate) &'a RawValue);
impl std::ops::Deref for RawSelf<'_> {
type Target = RawValue;
fn deref(&self) -> &Self::Target {
self.0
}
}
pub trait ForeignFunction<V> {
type ParameterCount;
const PARAMETER_COUNT: Self::ParameterCount;
fn into_raw_foreign_function(self) -> RawForeignFunction;
}
#[allow(missing_debug_implementations)]
pub mod ffvariants {
use std::marker::PhantomData;
pub struct Fallible<Args>(PhantomData<Args>);
pub struct Infallible<Args>(PhantomData<Args>);
pub enum VarargsFallible {}
pub enum VarargsInfallible {}
mod bare {
pub trait Sealed {}
impl<Args> Sealed for super::Fallible<Args> {}
impl<Args> Sealed for super::Infallible<Args> {}
impl Sealed for super::VarargsFallible {}
impl Sealed for super::VarargsInfallible {}
}
pub trait BareMaybeVarargs: bare::Sealed {}
impl<Args> BareMaybeVarargs for Fallible<Args> {}
impl<Args> BareMaybeVarargs for Infallible<Args> {}
impl BareMaybeVarargs for VarargsFallible {}
impl BareMaybeVarargs for VarargsInfallible {}
pub trait BareExactArgs: bare::Sealed {}
impl<Args> BareExactArgs for Fallible<Args> {}
impl<Args> BareExactArgs for Infallible<Args> {}
pub struct FallibleRawSelf<Args>(PhantomData<Args>);
pub struct InfallibleRawSelf<Args>(PhantomData<Args>);
pub struct FallibleSelf<S, Args>(PhantomData<(S, Args)>);
pub struct InfallibleSelf<S, Args>(PhantomData<(S, Args)>);
mod method {
pub trait Sealed {}
impl<Args> Sealed for super::FallibleRawSelf<Args> {}
impl<Args> Sealed for super::InfallibleRawSelf<Args> {}
impl<S, Args> Sealed for super::FallibleSelf<S, Args> {}
impl<S, Args> Sealed for super::InfallibleSelf<S, Args> {}
}
pub trait Receiver {
type Receiver;
}
pub struct ImmutableSelf<S>(PhantomData<S>);
pub struct MutableSelf<S>(PhantomData<S>);
impl<S> Receiver for ImmutableSelf<S> {
type Receiver = S;
}
impl<S> Receiver for MutableSelf<S> {
type Receiver = S;
}
pub trait Method<S>: method::Sealed
where
S: ?Sized,
{
}
impl<'s, Args> Method<super::RawSelf<'s>> for FallibleRawSelf<Args> {}
impl<'s, Args> Method<super::RawSelf<'s>> for InfallibleRawSelf<Args> {}
impl<S, Args> Method<S::Receiver> for FallibleSelf<S, Args> where S: Receiver {}
impl<S, Args> Method<S::Receiver> for InfallibleSelf<S, Args> where S: Receiver {}
}
impl<Ret, Err, F> ForeignFunction<ffvariants::VarargsFallible> for F
where
Ret: IntoValue + 'static,
Err: std::error::Error + 'static,
F: Fn(Arguments) -> Result<Ret, Err> + 'static,
{
type ParameterCount = FunctionParameterCount;
const PARAMETER_COUNT: Self::ParameterCount = FunctionParameterCount::Varargs;
fn into_raw_foreign_function(self) -> RawForeignFunction {
create_rawff(move |env, gc, args| {
self(Arguments::new(args, env))
.map(|value| value.into_value_with_environment(env).to_raw(gc))
.map_err(|error| LanguageErrorKind::User(Box::new(error)))
})
}
}
impl<Ret, F> ForeignFunction<ffvariants::VarargsInfallible> for F
where
Ret: IntoValue + 'static,
F: Fn(Arguments) -> Ret + 'static,
{
type ParameterCount = FunctionParameterCount;
const PARAMETER_COUNT: Self::ParameterCount = FunctionParameterCount::Varargs;
fn into_raw_foreign_function(self) -> RawForeignFunction {
create_rawff(move |env, gc, args| {
Ok(self(Arguments::new(args, env)).into_value_with_environment(env).to_raw(gc))
})
}
}