More efficient function representation

This commit is contained in:
Laurenz 2021-07-21 16:55:32 +02:00
parent 929f4d64fe
commit 927f1154fa

View File

@ -8,49 +8,49 @@ use crate::syntax::{Span, Spanned};
/// An evaluatable function. /// An evaluatable function.
#[derive(Clone)] #[derive(Clone)]
pub struct Function { pub struct Function(Rc<Repr<Func>>);
/// The name of the function.
/// /// The unsized representation behind the [`Rc`].
/// The string is boxed to make the whole struct fit into 24 bytes, so that struct Repr<T: ?Sized> {
/// a value fits into 32 bytes. name: Option<EcoString>,
name: Option<Box<EcoString>>, func: T,
/// The closure that defines the function.
f: Rc<dyn Fn(&mut EvalContext, &mut FuncArgs) -> Value>,
} }
type Func = dyn Fn(&mut EvalContext, &mut FuncArgs) -> Value;
impl Function { impl Function {
/// Create a new function from a rust closure. /// Create a new function from a rust closure.
pub fn new<F>(name: Option<EcoString>, f: F) -> Self pub fn new<F>(name: Option<EcoString>, func: F) -> Self
where where
F: Fn(&mut EvalContext, &mut FuncArgs) -> Value + 'static, F: Fn(&mut EvalContext, &mut FuncArgs) -> Value + 'static,
{ {
Self { name: name.map(Box::new), f: Rc::new(f) } Self(Rc::new(Repr { name, func }))
} }
/// The name of the function. /// The name of the function.
pub fn name(&self) -> Option<&EcoString> { pub fn name(&self) -> Option<&EcoString> {
self.name.as_ref().map(|s| &**s) self.0.name.as_ref()
} }
} }
impl Deref for Function { impl Deref for Function {
type Target = dyn Fn(&mut EvalContext, &mut FuncArgs) -> Value; type Target = Func;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
self.f.as_ref() &self.0.func
} }
} }
impl Debug for Function { impl Debug for Function {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("ValueFunc").field("name", &self.name).finish() f.debug_struct("ValueFunc").field("name", &self.0.name).finish()
} }
} }
impl PartialEq for Function { impl PartialEq for Function {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
// We cast to thin pointers because we don't want to compare vtables. // We cast to thin pointers for comparison.
Rc::as_ptr(&self.f) as *const () == Rc::as_ptr(&other.f) as *const () Rc::as_ptr(&self.0) as *const () == Rc::as_ptr(&other.0) as *const ()
} }
} }