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); pub type NativeFunctionImpl = Rc, &[Value]) -> Result + 'static>; #[derive(Clone)] pub struct NativeFunction { name: IdentifierValue, inner: NativeFunctionImpl, docstring: StringValue, } impl NativeFunction { pub fn new(name: S, docstring: D, function: F) -> Self where S: Into, D: Into, F: Fn(&mut Machine, &Rc, &[Value]) -> Result + '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, arguments: &[Value], ) -> Result { (self.inner)(machine, environment, arguments) } } impl Hash for NativeFunction { fn hash(&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, "", self.name, (&raw const *self.inner.as_ref()).addr() ) } } impl NativeValue { pub fn cast_rc(&self) -> Option> { Rc::downcast(self.0.clone()).ok() } pub fn cast_ref(&self) -> Option<&T> { self.0.as_any().downcast_ref() } } impl From> for NativeValue { fn from(value: Rc) -> 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, "", self.0) } }