Files
lysp/src/vm/value/native.rs
T

128 lines
3.0 KiB
Rust

use std::{
any::Any,
fmt,
hash::{Hash, Hasher},
rc::Rc,
};
use crate::{
error::MachineError,
vm::{
env::Environment,
machine::Machine,
value::{IdentifierValue, StringValue, Value},
},
};
pub trait NativeObject: Any + fmt::Debug + fmt::Display {
fn as_any(&self) -> &dyn Any;
}
#[derive(Clone, Debug)]
pub struct NativeValue(Rc<dyn NativeObject>);
pub type NativeFunctionImpl =
Rc<dyn Fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> + 'static>;
#[derive(Clone)]
pub struct NativeFunction {
name: IdentifierValue,
inner: NativeFunctionImpl,
docstring: StringValue,
}
impl NativeFunction {
pub fn new<S, D, F>(name: S, docstring: D, function: F) -> Self
where
S: Into<IdentifierValue>,
D: Into<StringValue>,
F: Fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> + 'static,
{
Self {
name: name.into(),
docstring: docstring.into(),
inner: Rc::new(function),
}
}
pub fn name(&self) -> &IdentifierValue {
&self.name
}
pub fn docstring(&self) -> &StringValue {
&self.docstring
}
pub fn invoke(
&self,
machine: &mut Machine,
environment: &Rc<Environment>,
arguments: &[Value],
) -> Result<Value, MachineError> {
(self.inner)(machine, environment, arguments)
}
}
impl Hash for NativeFunction {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
(&raw const *self.inner.as_ref()).addr().hash(state);
}
}
impl PartialEq for NativeFunction {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && Rc::ptr_eq(&self.inner, &other.inner)
}
}
impl Eq for NativeFunction {}
impl fmt::Debug for NativeFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NativeFunction")
.field("name", &self.name)
.field_with("inner", |f| write!(f, "{:p}", self.inner))
.finish()
}
}
impl fmt::Display for NativeFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"<native {}@{:#x}>",
self.name,
(&raw const *self.inner.as_ref()).addr()
)
}
}
impl NativeValue {
pub fn cast_rc<T: NativeObject>(&self) -> Option<Rc<T>> {
Rc::downcast(self.0.clone()).ok()
}
pub fn cast_ref<T: NativeObject>(&self) -> Option<&T> {
self.0.as_any().downcast_ref()
}
}
impl From<Rc<dyn NativeObject + 'static>> for NativeValue {
fn from(value: Rc<dyn NativeObject>) -> Self {
Self(value)
}
}
impl PartialEq for NativeValue {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}
impl fmt::Display for NativeValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<native {}>", self.0)
}
}