It turns out that rust can't really reason about the relationship between the runtime lifetime and the context lifetime in a way that is actually usable. This removes the lifetime stuff in favor of reference counting the runtime itself, via a block that we embed in the pointer. This, I think, it the least worst option here.
189 lines
5.3 KiB
Rust
189 lines
5.3 KiB
Rust
use super::{TryFromValue, TryIntoValue};
|
|
use crate::{ContextRef, Error, ValueRef, ValueResult};
|
|
use std::marker::PhantomData;
|
|
|
|
pub trait IntoRustFunctionResult {
|
|
fn into_res(self, ctx: &ContextRef) -> ValueResult;
|
|
}
|
|
|
|
impl<T: TryIntoValue> IntoRustFunctionResult for T {
|
|
fn into_res(self, ctx: &ContextRef) -> ValueResult {
|
|
self.try_into_value(ctx)
|
|
}
|
|
}
|
|
|
|
impl<T: TryIntoValue, E: std::fmt::Display> IntoRustFunctionResult for core::result::Result<T, E> {
|
|
fn into_res(self, ctx: &ContextRef) -> ValueResult {
|
|
match self {
|
|
Ok(v) => v.try_into_value(ctx),
|
|
Err(e) => Err(Error::RustFunctionError(e.to_string())),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait RustFunction<F> {
|
|
fn argument_count() -> usize;
|
|
fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult;
|
|
}
|
|
|
|
impl<R, F> RustFunction<PhantomData<(&R, &F)>> for F
|
|
where
|
|
R: IntoRustFunctionResult,
|
|
F: Fn(&ContextRef) -> R + Sized,
|
|
{
|
|
fn argument_count() -> usize {
|
|
0
|
|
}
|
|
|
|
fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult {
|
|
if args.len() != 0 {
|
|
return Err(Error::ArgumentCountMismatch {
|
|
expected: Self::argument_count(),
|
|
received: args.len(),
|
|
});
|
|
}
|
|
|
|
let res = self(context);
|
|
res.into_res(context)
|
|
}
|
|
}
|
|
|
|
impl<R, A, F> RustFunction<PhantomData<(&R, &A, &F)>> for F
|
|
where
|
|
R: IntoRustFunctionResult,
|
|
A: TryFromValue,
|
|
F: Fn(&ContextRef, A) -> R + Sized,
|
|
{
|
|
fn argument_count() -> usize {
|
|
1
|
|
}
|
|
|
|
fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult {
|
|
if args.len() != Self::argument_count() {
|
|
return Err(Error::ArgumentCountMismatch {
|
|
expected: Self::argument_count(),
|
|
received: args.len(),
|
|
});
|
|
}
|
|
|
|
let va = A::try_from_value(args[0], &context)?;
|
|
let res = self(context, va);
|
|
res.into_res(context)
|
|
}
|
|
}
|
|
|
|
impl<R, A, B, F> RustFunction<PhantomData<(&R, &A, &B, &F)>> for F
|
|
where
|
|
R: IntoRustFunctionResult,
|
|
A: TryFromValue,
|
|
B: TryFromValue,
|
|
F: Fn(&ContextRef, A, B) -> R + Sized,
|
|
{
|
|
fn argument_count() -> usize {
|
|
2
|
|
}
|
|
|
|
fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult {
|
|
if args.len() != Self::argument_count() {
|
|
return Err(Error::ArgumentCountMismatch {
|
|
expected: Self::argument_count(),
|
|
received: args.len(),
|
|
});
|
|
}
|
|
|
|
let va = A::try_from_value(args[0], &context)?;
|
|
let vb = B::try_from_value(args[1], &context)?;
|
|
let res = self(context, va, vb);
|
|
res.into_res(context)
|
|
}
|
|
}
|
|
|
|
impl<R, A, B, C, F> RustFunction<PhantomData<(&R, &A, &B, &C, &F)>> for F
|
|
where
|
|
R: IntoRustFunctionResult,
|
|
A: TryFromValue,
|
|
B: TryFromValue,
|
|
C: TryFromValue,
|
|
F: Fn(&ContextRef, A, B, C) -> R + Sized,
|
|
{
|
|
fn argument_count() -> usize {
|
|
3
|
|
}
|
|
|
|
fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult {
|
|
if args.len() != Self::argument_count() {
|
|
return Err(Error::ArgumentCountMismatch {
|
|
expected: Self::argument_count(),
|
|
received: args.len(),
|
|
});
|
|
}
|
|
|
|
let va = A::try_from_value(args[0], &context)?;
|
|
let vb = B::try_from_value(args[1], &context)?;
|
|
let vc = C::try_from_value(args[2], &context)?;
|
|
let res = self(context, va, vb, vc);
|
|
res.into_res(context)
|
|
}
|
|
}
|
|
|
|
impl<R, A, B, C, D, F> RustFunction<PhantomData<(&R, &A, &B, &C, &D, &F)>> for F
|
|
where
|
|
R: IntoRustFunctionResult,
|
|
A: TryFromValue,
|
|
B: TryFromValue,
|
|
C: TryFromValue,
|
|
D: TryFromValue,
|
|
F: Fn(&ContextRef, A, B, C, D) -> R + Sized,
|
|
{
|
|
fn argument_count() -> usize {
|
|
4
|
|
}
|
|
|
|
fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult {
|
|
if args.len() != Self::argument_count() {
|
|
return Err(Error::ArgumentCountMismatch {
|
|
expected: Self::argument_count(),
|
|
received: args.len(),
|
|
});
|
|
}
|
|
|
|
let va = A::try_from_value(args[0], &context)?;
|
|
let vb = B::try_from_value(args[1], &context)?;
|
|
let vc = C::try_from_value(args[2], &context)?;
|
|
let vd = D::try_from_value(args[3], &context)?;
|
|
let res = self(context, va, vb, vc, vd);
|
|
res.into_res(context)
|
|
}
|
|
}
|
|
|
|
impl<R, A, B, C, D, E, F> RustFunction<PhantomData<(&R, &A, &B, &C, &D, &E, &F)>> for F
|
|
where
|
|
R: IntoRustFunctionResult,
|
|
A: TryFromValue,
|
|
B: TryFromValue,
|
|
C: TryFromValue,
|
|
D: TryFromValue,
|
|
E: TryFromValue,
|
|
F: Fn(&ContextRef, A, B, C, D, E) -> R + Sized,
|
|
{
|
|
fn argument_count() -> usize {
|
|
5
|
|
}
|
|
|
|
fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult {
|
|
if args.len() != Self::argument_count() {
|
|
return Err(Error::ArgumentCountMismatch {
|
|
expected: Self::argument_count(),
|
|
received: args.len(),
|
|
});
|
|
}
|
|
|
|
let va = A::try_from_value(args[0], &context)?;
|
|
let vb = B::try_from_value(args[1], &context)?;
|
|
let vc = C::try_from_value(args[2], &context)?;
|
|
let vd = D::try_from_value(args[3], &context)?;
|
|
let ve = E::try_from_value(args[4], &context)?;
|
|
let res = self(context, va, vb, vc, vd, ve);
|
|
res.into_res(context)
|
|
}
|
|
}
|