use crate::gc::{Finalize, Trace};
use crate::lang::*;
use crate::runtime::*;
use crate::stdlib::*;
use crate::*;
use std::{fmt::Debug, mem::transmute, rc::Rc};
#[derive(Debug, Clone, Trace, Finalize)]
#[rust_cc(unsafe_no_drop)]
pub(crate) struct CapturedVar {
#[rust_cc(ignore)]
pub(crate) name: Identifier,
pub(crate) var: RantyVar,
}
#[derive(Clone, Trace, Finalize)]
#[rust_cc(unsafe_no_drop)]
pub(crate) struct RantyNativeFunction {
#[rust_cc(ignore)]
pub(crate) callback:
unsafe fn(&mut VM, Vec<RantyValue>, &[RantyValue], *const ()) -> RantyStdResult,
#[rust_cc(ignore)]
pub(crate) callback_data: *const (),
pub(crate) captures: Vec<RantyValue>,
}
impl Debug for RantyNativeFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:p}", self.callback_data)
}
}
#[derive(Debug, Trace, Finalize)]
#[rust_cc(unsafe_no_drop)]
pub struct RantyFunction {
#[rust_cc(ignore)]
pub(crate) params: Rc<Vec<Parameter>>,
#[rust_cc(ignore)]
pub(crate) min_arg_count: usize,
#[rust_cc(ignore)]
pub(crate) vararg_start_index: usize,
pub(crate) captured_vars: Vec<CapturedVar>,
pub(crate) body: RantyFunctionInterface,
#[rust_cc(ignore)]
pub(crate) flavor: Option<StackFrameFlavor>,
}
impl RantyFunction {
#[inline]
pub fn is_variadic(&self) -> bool {
self.vararg_start_index < self.params.len() || self.vararg_start_index < self.min_arg_count
}
#[inline]
pub fn is_native(&self) -> bool {
matches!(self.body, RantyFunctionInterface::Foreign(_))
}
#[inline]
pub fn has_lazy_params(&self) -> bool {
self.params.iter().any(|param| param.is_lazy)
}
pub fn from_native<P: FromRantyArgs>(func: fn(&mut VM, P) -> RantyStdResult) -> Self {
fn erased<P: FromRantyArgs>(
vm: &mut VM,
args: Vec<RantyValue>,
_captures: &[RantyValue],
callback_data: *const (),
) -> RantyStdResult {
let callback: fn(&mut VM, P) -> RantyStdResult = unsafe { transmute(callback_data) };
callback(vm, P::from_ranty_args(args).into_runtime_result()?)
}
Self::build_foreign(
RantyNativeFunction {
callback: erased::<P>,
callback_data: func as *const (),
captures: vec![],
},
P::as_ranty_params(),
)
}
pub fn from_captured_native<P: FromRantyArgs>(
captures: Vec<RantyValue>,
func: fn(&mut VM, P, &[RantyValue]) -> RantyStdResult,
) -> Self {
fn erased<P: FromRantyArgs>(
vm: &mut VM,
args: Vec<RantyValue>,
captures: &[RantyValue],
callback_data: *const (),
) -> RantyStdResult {
let callback: fn(&mut VM, P, &[RantyValue]) -> RantyStdResult =
unsafe { transmute(callback_data) };
callback(
vm,
P::from_ranty_args(args).into_runtime_result()?,
captures,
)
}
Self::build_foreign(
RantyNativeFunction {
callback: erased::<P>,
callback_data: func as *const (),
captures,
},
P::as_ranty_params(),
)
}
fn build_foreign(native: RantyNativeFunction, params: Vec<Parameter>) -> Self {
let params = Rc::new(params);
Self {
body: RantyFunctionInterface::Foreign(native),
captured_vars: vec![],
min_arg_count: params.iter().take_while(|p| p.is_required()).count(),
vararg_start_index: params
.iter()
.enumerate()
.find_map(|(i, p)| p.varity.is_variadic().then_some(i))
.unwrap_or_else(|| params.len()),
params,
flavor: None,
}
}
}
#[derive(Clone, Trace, Finalize)]
#[rust_cc(unsafe_no_drop)]
pub(crate) enum RantyFunctionInterface {
Foreign(RantyNativeFunction),
#[rust_cc(ignore)]
User(Rc<Sequence>),
}
impl Debug for RantyFunctionInterface {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RantyFunctionInterface::Foreign(func) => write!(f, "{:p}", func.callback_data),
RantyFunctionInterface::User(func) => write!(f, "{:#p}", Rc::as_ptr(func)),
}
}
}