use std::borrow::BorrowMut;
use emacs_module::emacs_value;
use emacs_macros;
use crate::{Env, Value, Result, IntoLisp, global::{GlobalRef, OnceGlobalRef}};
pub unsafe trait IntoLispArgs<'e> {
type LispArgs: BorrowMut<[emacs_value]>;
fn into_lisp_args(self, env: &'e Env) -> Result<Self::LispArgs>;
}
impl<'e> Value<'e> {
#[inline]
pub fn call<A>(self, args: A) -> Result<Value<'e>> where A: IntoLispArgs<'e> {
unsafe { self.call_unprotected(args).map(|v| v.protect()) }
}
#[allow(unused_unsafe)]
pub unsafe fn call_unprotected<A>(self, args: A) -> Result<Value<'e>> where A: IntoLispArgs<'e> {
let env = self.env;
let mut lisp_args = args.into_lisp_args(env)?;
let lisp_args: &mut [emacs_value] = lisp_args.borrow_mut();
let ptr = lisp_args.as_mut_ptr();
let length = lisp_args.len() as isize;
unsafe_raw_call_value_unprotected!(env, funcall, self.raw, length, ptr)
}
}
pub trait IntoLispCallable<'e> {
fn into_lisp_callable(self, env: &'e Env) -> Result<Value<'e>>;
}
impl Env {
#[inline]
pub fn call<'e, F, A>(&'e self, func: F, args: A) -> Result<Value<'_>>
where
F: IntoLispCallable<'e>,
A: IntoLispArgs<'e>,
{
func.into_lisp_callable(self)?.call(args)
}
#[inline]
pub unsafe fn call_unprotected<'e, F, A>(&'e self, func: F, args: A) -> Result<Value<'_>>
where
F: IntoLispCallable<'e>,
A: IntoLispArgs<'e>,
{
func.into_lisp_callable(self)?.call_unprotected(args)
}
}
impl GlobalRef {
#[inline]
pub fn call<'e, A>(&'e self, env: &'e Env, args: A) -> Result<Value<'_>>
where
A: IntoLispArgs<'e>,
{
self.bind(env).call(args)
}
#[inline]
pub unsafe fn call_unprotected<'e, A>(&'e self, env: &'e Env, args: A) -> Result<Value<'_>>
where
A: IntoLispArgs<'e>,
{
self.bind(env).call_unprotected(args)
}
}
unsafe impl<'e, T: AsRef<[Value<'e>]> + ?Sized> IntoLispArgs<'e> for &T {
type LispArgs = Vec<emacs_value>;
fn into_lisp_args(self, _: &'e Env) -> Result<Self::LispArgs> {
Ok(self.as_ref().iter().map(|v| v.raw).collect())
}
}
emacs_macros::impl_lisp_args_for_tuples!(12);
emacs_macros::impl_lisp_args_for_arrays!(12);
impl<'e> IntoLispCallable<'e> for Value<'e> {
#[inline(always)]
fn into_lisp_callable(self, _: &'e Env) -> Result<Value<'e>> {
Ok(self)
}
}
impl<'e, T: AsRef<str>> IntoLispCallable<'e> for T {
#[inline(always)]
fn into_lisp_callable(self, env: &'e Env) -> Result<Value<'e>> {
env.intern(self.as_ref())
}
}
impl<'e> IntoLispCallable<'e> for &'e GlobalRef {
#[inline(always)]
fn into_lisp_callable(self, env: &'e Env) -> Result<Value<'e>> {
self.bind(env).into_lisp_callable(env)
}
}
impl<'e> IntoLispCallable<'e> for &'e OnceGlobalRef {
#[inline(always)]
fn into_lisp_callable(self, env: &'e Env) -> Result<Value<'e>> {
self.bind(env).into_lisp_callable(env)
}
}