use crate::context::Handler;
use crate::VmErrorKind;
use crate::{
Args, Call, ConstValue, Context, FromValue, RawRef, Ref, Rtti, Shared, Stack, Tuple, Unit,
UnsafeFromValue, Value, VariantRtti, Vm, VmCall, VmError, VmHalt,
};
use std::fmt;
use std::sync::Arc;
pub type Function = FunctionImpl<Value>;
pub type SyncFunction = FunctionImpl<ConstValue>;
pub struct FunctionImpl<V>
where
V: Clone,
Tuple: From<Box<[V]>>,
{
inner: Inner<V>,
}
impl<V> FunctionImpl<V>
where
V: Clone,
Tuple: From<Box<[V]>>,
{
pub fn call<A, T>(&self, args: A) -> Result<T, VmError>
where
A: Args,
T: FromValue,
{
let value = match &self.inner {
Inner::FnHandler(handler) => {
let arg_count = args.count();
let mut stack = Stack::with_capacity(arg_count);
args.into_stack(&mut stack)?;
(handler.handler)(&mut stack, arg_count)?;
stack.pop()?
}
Inner::FnOffset(fn_offset) => fn_offset.call(args, ())?,
Inner::FnClosureOffset(closure) => closure
.fn_offset
.call(args, (Tuple::from(closure.environment.clone()),))?,
Inner::FnUnitStruct(empty) => {
Self::check_args(args.count(), 0)?;
Value::unit_struct(empty.rtti.clone())
}
Inner::FnTupleStruct(tuple) => {
Self::check_args(args.count(), tuple.args)?;
Value::tuple_struct(tuple.rtti.clone(), args.into_vec()?)
}
Inner::FnUnitVariant(empty) => {
Self::check_args(args.count(), 0)?;
Value::empty_variant(empty.rtti.clone())
}
Inner::FnTupleVariant(tuple) => {
Self::check_args(args.count(), tuple.args)?;
Value::tuple_variant(tuple.rtti.clone(), args.into_vec()?)
}
};
Ok(T::from_value(value)?)
}
pub(crate) fn call_with_vm(&self, vm: &mut Vm, args: usize) -> Result<Option<VmHalt>, VmError> {
let reason = match &self.inner {
Inner::FnHandler(handler) => {
let _guard = crate::interface::EnvGuard::new(&vm.context, &vm.unit);
(handler.handler)(&mut vm.stack, args)?;
None
}
Inner::FnOffset(fn_offset) => {
if let Some(vm_call) = fn_offset.call_with_vm(vm, args, ())? {
return Ok(Some(VmHalt::VmCall(vm_call)));
}
None
}
Inner::FnClosureOffset(closure) => {
if let Some(vm_call) = closure.fn_offset.call_with_vm(
vm,
args,
(Tuple::from(closure.environment.clone()),),
)? {
return Ok(Some(VmHalt::VmCall(vm_call)));
}
None
}
Inner::FnUnitStruct(empty) => {
Self::check_args(args, 0)?;
vm.stack_mut().push(Value::unit_struct(empty.rtti.clone()));
None
}
Inner::FnTupleStruct(tuple) => {
Self::check_args(args, tuple.args)?;
let value =
Value::tuple_struct(tuple.rtti.clone(), vm.stack_mut().pop_sequence(args)?);
vm.stack_mut().push(value);
None
}
Inner::FnUnitVariant(tuple) => {
Self::check_args(args, 0)?;
let value = Value::empty_variant(tuple.rtti.clone());
vm.stack_mut().push(value);
None
}
Inner::FnTupleVariant(tuple) => {
Self::check_args(args, tuple.args)?;
let value =
Value::tuple_variant(tuple.rtti.clone(), vm.stack_mut().pop_sequence(args)?);
vm.stack_mut().push(value);
None
}
};
Ok(reason)
}
pub(crate) fn from_handler(handler: Arc<Handler>) -> Self {
Self {
inner: Inner::FnHandler(FnHandler { handler }),
}
}
pub(crate) fn from_offset(
context: Arc<Context>,
unit: Arc<Unit>,
offset: usize,
call: Call,
args: usize,
) -> Self {
Self {
inner: Inner::FnOffset(FnOffset {
context,
unit,
offset,
call,
args,
}),
}
}
pub(crate) fn from_closure(
context: Arc<Context>,
unit: Arc<Unit>,
offset: usize,
call: Call,
args: usize,
environment: Box<[V]>,
) -> Self {
Self {
inner: Inner::FnClosureOffset(FnClosureOffset {
fn_offset: FnOffset {
context,
unit,
offset,
call,
args,
},
environment,
}),
}
}
pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
Self {
inner: Inner::FnUnitStruct(FnUnitStruct { rtti }),
}
}
pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
Self {
inner: Inner::FnTupleStruct(FnTupleStruct { rtti, args }),
}
}
pub(crate) fn from_empty_variant(rtti: Arc<VariantRtti>) -> Self {
Self {
inner: Inner::FnUnitVariant(FnUnitVariant { rtti }),
}
}
pub(crate) fn from_tuple_variant(rtti: Arc<VariantRtti>, args: usize) -> Self {
Self {
inner: Inner::FnTupleVariant(FnTupleVariant { rtti, args }),
}
}
#[inline]
fn check_args(actual: usize, expected: usize) -> Result<(), VmError> {
if actual != expected {
return Err(VmError::from(VmErrorKind::BadArgumentCount {
expected,
actual,
}));
}
Ok(())
}
}
impl FunctionImpl<Value> {
pub fn into_sync(self) -> Result<SyncFunction, VmError> {
let inner = match self.inner {
Inner::FnClosureOffset(closure) => {
let mut env = Vec::with_capacity(closure.environment.len());
for value in closure.environment.into_vec() {
env.push(ConstValue::from_value(value)?);
}
Inner::FnClosureOffset(FnClosureOffset {
fn_offset: closure.fn_offset,
environment: env.into_boxed_slice(),
})
}
Inner::FnHandler(inner) => Inner::FnHandler(inner),
Inner::FnOffset(inner) => Inner::FnOffset(inner),
Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner),
Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner),
Inner::FnUnitVariant(inner) => Inner::FnUnitVariant(inner),
Inner::FnTupleVariant(inner) => Inner::FnTupleVariant(inner),
};
Ok(SyncFunction { inner })
}
}
impl fmt::Debug for Function {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
Inner::FnHandler(handler) => {
write!(f, "native function ({:p})", handler.handler.as_ref())?;
}
Inner::FnOffset(offset) => {
write!(f, "dynamic function (at: 0x{:x})", offset.offset)?;
}
Inner::FnClosureOffset(closure) => {
write!(
f,
"closure (at: 0x{:x}, env:{:?})",
closure.fn_offset.offset, closure.environment
)?;
}
Inner::FnUnitStruct(empty) => {
write!(f, "empty {}", empty.rtti.item)?;
}
Inner::FnTupleStruct(tuple) => {
write!(f, "tuple {}", tuple.rtti.item)?;
}
Inner::FnUnitVariant(empty) => {
write!(f, "variant empty {}", empty.rtti.item)?;
}
Inner::FnTupleVariant(tuple) => {
write!(f, "variant tuple {}", tuple.rtti.item)?;
}
}
Ok(())
}
}
#[derive(Debug)]
enum Inner<V> {
FnHandler(FnHandler),
FnOffset(FnOffset),
FnClosureOffset(FnClosureOffset<V>),
FnUnitStruct(FnUnitStruct),
FnTupleStruct(FnTupleStruct),
FnUnitVariant(FnUnitVariant),
FnTupleVariant(FnTupleVariant),
}
struct FnHandler {
handler: Arc<Handler>,
}
impl fmt::Debug for FnHandler {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FnHandler")
}
}
#[derive(Clone)]
struct FnOffset {
context: Arc<Context>,
unit: Arc<Unit>,
offset: usize,
call: Call,
args: usize,
}
impl FnOffset {
fn call<A, E>(&self, args: A, extra: E) -> Result<Value, VmError>
where
A: Args,
E: Args,
{
Function::check_args(args.count(), self.args)?;
let mut vm = Vm::new(self.context.clone(), self.unit.clone());
vm.set_ip(self.offset);
args.into_stack(vm.stack_mut())?;
extra.into_stack(vm.stack_mut())?;
self.call.call_with_vm(vm)
}
fn call_with_vm<E>(&self, vm: &mut Vm, args: usize, extra: E) -> Result<Option<VmCall>, VmError>
where
E: Args,
{
Function::check_args(args, self.args)?;
if let Call::Immediate = self.call {
if vm.is_same(&self.context, &self.unit) {
vm.push_call_frame(self.offset, args)?;
extra.into_stack(vm.stack_mut())?;
return Ok(None);
}
}
let mut new_stack = vm.stack_mut().drain_stack_top(args)?.collect::<Stack>();
extra.into_stack(&mut new_stack)?;
let mut vm = Vm::new_with_stack(self.context.clone(), self.unit.clone(), new_stack);
vm.set_ip(self.offset);
Ok(Some(VmCall::new(self.call, vm)))
}
}
impl fmt::Debug for FnOffset {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FnOffset")
.field("context", &(&self.context as *const _))
.field("unit", &(&self.unit as *const _))
.field("offset", &self.offset)
.field("call", &self.call)
.field("args", &self.args)
.finish()
}
}
#[derive(Debug)]
struct FnClosureOffset<V> {
fn_offset: FnOffset,
environment: Box<[V]>,
}
#[derive(Debug)]
struct FnUnitStruct {
rtti: Arc<Rtti>,
}
#[derive(Debug)]
struct FnTupleStruct {
rtti: Arc<Rtti>,
args: usize,
}
#[derive(Debug)]
struct FnUnitVariant {
rtti: Arc<VariantRtti>,
}
#[derive(Debug)]
struct FnTupleVariant {
rtti: Arc<VariantRtti>,
args: usize,
}
impl FromValue for SyncFunction {
fn from_value(value: Value) -> Result<Self, VmError> {
Ok(value.into_function()?.take()?.into_sync()?)
}
}
impl FromValue for Function {
fn from_value(value: Value) -> Result<Self, VmError> {
Ok(value.into_function()?.take()?)
}
}
impl FromValue for Shared<Function> {
fn from_value(value: Value) -> Result<Self, VmError> {
Ok(value.into_function()?)
}
}
impl FromValue for Ref<Function> {
fn from_value(value: Value) -> Result<Self, VmError> {
Ok(value.into_function()?.into_ref()?)
}
}
impl UnsafeFromValue for &Function {
type Output = *const Function;
type Guard = RawRef;
fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
let function = value.into_function()?;
let (function, guard) = Ref::into_raw(function.into_ref()?);
Ok((function, guard))
}
unsafe fn unsafe_coerce(output: Self::Output) -> Self {
&*output
}
}
#[cfg(test)]
mod tests {
use super::SyncFunction;
fn assert_send<T>()
where
T: Send,
{
}
fn assert_sync<T>()
where
T: Sync,
{
}
#[test]
fn assert_send_sync() {
assert_send::<SyncFunction>();
assert_sync::<SyncFunction>();
}
}