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

View File

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