More efficient function representation

This commit is contained in:
Laurenz 2023-03-19 23:49:35 +01:00
parent ab43bd802e
commit 30d6c070c1
3 changed files with 45 additions and 46 deletions

View File

@ -115,8 +115,8 @@ fn create(func: &Func) -> TokenStream {
let params = params.iter().map(create_param_info); let params = params.iter().map(create_param_info);
quote! { quote! {
#[doc = #docs] #[doc = #docs]
#vis fn #ident() -> ::typst::eval::NativeFunc { #vis fn #ident() -> &'static ::typst::eval::NativeFunc {
::typst::eval::NativeFunc { static FUNC: ::typst::eval::NativeFunc = ::typst::eval::NativeFunc {
func: |vm, args| { func: |vm, args| {
#(#handlers)* #(#handlers)*
#[allow(unreachable_code)] #[allow(unreachable_code)]
@ -130,7 +130,8 @@ fn create(func: &Func) -> TokenStream {
returns: ::std::vec![#(#returns),*], returns: ::std::vec![#(#returns),*],
category: #category, category: #category,
}), }),
} };
&FUNC
} }
} }
} }

View File

@ -20,42 +20,42 @@ use crate::World;
#[derive(Clone, Hash)] #[derive(Clone, Hash)]
pub struct Func { pub struct Func {
/// The internal representation. /// The internal representation.
repr: Arc<Prehashed<Repr>>, repr: Repr,
/// The span with which errors are reported when this function is called. /// The span with which errors are reported when this function is called.
span: Span, span: Span,
} }
/// The different kinds of function representations. /// The different kinds of function representations.
#[derive(Hash)] #[derive(Clone, PartialEq, Hash)]
enum Repr { enum Repr {
/// A native Rust function. /// A native Rust function.
Native(NativeFunc), Native(&'static NativeFunc),
/// A function for an element. /// A function for an element.
Elem(ElemFunc), Elem(ElemFunc),
/// A user-defined closure. /// A user-defined closure.
Closure(Closure), Closure(Arc<Prehashed<Closure>>),
/// A nested function with pre-applied arguments. /// A nested function with pre-applied arguments.
With(Func, Args), With(Arc<(Func, Args)>),
} }
impl Func { impl Func {
/// The name of the function. /// The name of the function.
pub fn name(&self) -> Option<&str> { pub fn name(&self) -> Option<&str> {
match &**self.repr { match &self.repr {
Repr::Native(native) => Some(native.info.name), Repr::Native(native) => Some(native.info.name),
Repr::Elem(func) => Some(func.info().name), Repr::Elem(func) => Some(func.info().name),
Repr::Closure(closure) => closure.name.as_deref(), Repr::Closure(closure) => closure.name.as_deref(),
Repr::With(func, _) => func.name(), Repr::With(arc) => arc.0.name(),
} }
} }
/// Extract details the function. /// Extract details the function.
pub fn info(&self) -> Option<&FuncInfo> { pub fn info(&self) -> Option<&FuncInfo> {
match &**self.repr { match &self.repr {
Repr::Native(native) => Some(&native.info), Repr::Native(native) => Some(&native.info),
Repr::Elem(func) => Some(func.info()), Repr::Elem(func) => Some(func.info()),
Repr::With(func, _) => func.info(), Repr::Closure(_) => None,
_ => None, Repr::With(arc) => arc.0.info(),
} }
} }
@ -74,10 +74,10 @@ impl Func {
/// The number of positional arguments this function takes, if known. /// The number of positional arguments this function takes, if known.
pub fn argc(&self) -> Option<usize> { pub fn argc(&self) -> Option<usize> {
match &**self.repr { match &self.repr {
Repr::Closure(closure) => closure.argc(), Repr::Closure(closure) => closure.argc(),
Repr::With(wrapped, applied) => Some(wrapped.argc()?.saturating_sub( Repr::With(arc) => Some(arc.0.argc()?.saturating_sub(
applied.items.iter().filter(|arg| arg.name.is_none()).count(), arc.1.items.iter().filter(|arg| arg.name.is_none()).count(),
)), )),
_ => None, _ => None,
} }
@ -85,7 +85,7 @@ impl Func {
/// Call the function with the given arguments. /// Call the function with the given arguments.
pub fn call_vm(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> { pub fn call_vm(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> {
match &**self.repr { match &self.repr {
Repr::Native(native) => { Repr::Native(native) => {
let value = (native.func)(vm, &mut args)?; let value = (native.func)(vm, &mut args)?;
args.finish()?; args.finish()?;
@ -113,9 +113,9 @@ impl Func {
args, args,
) )
} }
Repr::With(wrapped, applied) => { Repr::With(arc) => {
args.items = applied.items.iter().cloned().chain(args.items).collect(); args.items = arc.1.items.iter().cloned().chain(args.items).collect();
return wrapped.call_vm(vm, args); return arc.0.call_vm(vm, args);
} }
} }
} }
@ -137,15 +137,12 @@ impl Func {
/// Apply the given arguments to the function. /// Apply the given arguments to the function.
pub fn with(self, args: Args) -> Self { pub fn with(self, args: Args) -> Self {
let span = self.span; let span = self.span;
Self { Self { repr: Repr::With(Arc::new((self, args))), span }
repr: Arc::new(Prehashed::new(Repr::With(self, args))),
span,
}
} }
/// Extract the element function, if it is one. /// Extract the element function, if it is one.
pub fn element(&self) -> Option<ElemFunc> { pub fn element(&self) -> Option<ElemFunc> {
match **self.repr { match self.repr {
Repr::Elem(func) => Some(func), Repr::Elem(func) => Some(func),
_ => None, _ => None,
} }
@ -169,10 +166,7 @@ impl PartialEq for Func {
impl From<Repr> for Func { impl From<Repr> for Func {
fn from(repr: Repr) -> Self { fn from(repr: Repr) -> Self {
Self { Self { repr, span: Span::detached() }
repr: Arc::new(Prehashed::new(repr)),
span: Span::detached(),
}
} }
} }
@ -190,28 +184,32 @@ pub struct NativeFunc {
pub info: Lazy<FuncInfo>, pub info: Lazy<FuncInfo>,
} }
impl PartialEq for NativeFunc {
fn eq(&self, other: &Self) -> bool {
self.func as usize == other.func as usize
}
}
impl Eq for NativeFunc {}
impl Hash for NativeFunc { impl Hash for NativeFunc {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
(self.func as usize).hash(state); (self.func as usize).hash(state);
} }
} }
impl From<NativeFunc> for Func { impl From<&'static NativeFunc> for Func {
fn from(native: NativeFunc) -> Self { fn from(native: &'static NativeFunc) -> Self {
Repr::Native(native).into() Repr::Native(native).into()
} }
} }
cast_to_value! {
v: NativeFunc => Value::Func(v.into())
}
impl<F> From<F> for Value impl<F> From<F> for Value
where where
F: Fn() -> NativeFunc, F: Fn() -> &'static NativeFunc,
{ {
fn from(f: F) -> Self { fn from(f: F) -> Self {
f().into() Value::Func(f().into())
} }
} }
@ -294,7 +292,7 @@ impl Closure {
depth: usize, depth: usize,
mut args: Args, mut args: Args,
) -> SourceResult<Value> { ) -> SourceResult<Value> {
let closure = match &**this.repr { let closure = match &this.repr {
Repr::Closure(closure) => closure, Repr::Closure(closure) => closure,
_ => panic!("`this` must be a closure"), _ => panic!("`this` must be a closure"),
}; };
@ -347,7 +345,7 @@ impl Closure {
result result
} }
/// The number of positional arguments this function takes, if known. /// The number of positional arguments this closure takes, if known.
fn argc(&self) -> Option<usize> { fn argc(&self) -> Option<usize> {
if self.sink.is_some() { if self.sink.is_some() {
return None; return None;
@ -359,7 +357,7 @@ impl Closure {
impl From<Closure> for Func { impl From<Closure> for Func {
fn from(closure: Closure) -> Self { fn from(closure: Closure) -> Self {
Repr::Closure(closure).into() Repr::Closure(Arc::new(Prehashed::new(closure))).into()
} }
} }

View File

@ -88,12 +88,6 @@ impl Debug for ElemFunc {
} }
} }
impl Hash for ElemFunc {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_usize(self.0 as *const _ as usize);
}
}
impl Eq for ElemFunc {} impl Eq for ElemFunc {}
impl PartialEq for ElemFunc { impl PartialEq for ElemFunc {
@ -102,6 +96,12 @@ impl PartialEq for ElemFunc {
} }
} }
impl Hash for ElemFunc {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_usize(self.0 as *const _ as usize);
}
}
cast_from_value! { cast_from_value! {
ElemFunc, ElemFunc,
v: Func => v.element().ok_or("expected element function")?, v: Func => v.element().ok_or("expected element function")?,