Use one central thread_local for builtin function types

Instead of occupying multiple TLS slots, introduce a single type
that stores all the builtin function types in members. Use a macro
to define this struct then, which allows us to use a nice DSL to
define these function types, reducing the boiler plate significantly.

The downside is that we no longer have the ability to easily share
semantically equivalent function types (e.g. for `Round`, `Ceil`
and `Floor` etc.). Doing so would require us to introdue a separate
name for these types, and then use external matching to map the
BuiltinFunctions to the reduced list of types. The performance impact
is minimal though, so this is not done to KISS.
This commit is contained in:
Milian Wolff 2024-10-27 14:59:36 +01:00 committed by Olivier Goffart
parent 6ff8abfb1a
commit df1dd3b6cf

View file

@ -107,91 +107,62 @@ pub enum BuiltinMacroFunction {
Debug, Debug,
} }
impl BuiltinFunction { macro_rules! declare_builtin_function_types {
pub fn ty(&self) -> Type { ($( $Name:ident $(($Pattern:tt))? : ($( $Arg:expr ),*) -> $ReturnType:expr $(,)? )*) => {
macro_rules! interned_type { #[allow(non_snake_case)]
( $x:expr ) => {{ pub struct BuiltinFunctionTypes {
thread_local! { $(pub $Name : Type),*
static TYPE: Type = Type::Function(Rc::new($x)); }
impl BuiltinFunctionTypes {
pub fn new() -> Self {
Self {
$($Name : Type::Function(Rc::new(Function{
args: vec![$($Arg),*],
return_type: $ReturnType,
}))),*
} }
TYPE.with(|t| t.clone())
}};
} }
match self { pub fn ty(&self, function: &BuiltinFunction) -> Type {
BuiltinFunction::GetWindowScaleFactor => interned_type!(Function { match function {
return_type: Type::UnitProduct(vec![(Unit::Phx, 1), (Unit::Px, -1)]), $(BuiltinFunction::$Name $(($Pattern))? => self.$Name.clone()),*
args: vec![],
}),
BuiltinFunction::GetWindowDefaultFontSize => {
interned_type!(Function { return_type: Type::LogicalLength, args: vec![] })
} }
BuiltinFunction::AnimationTick => {
interned_type!(Function { return_type: Type::Duration.into(), args: vec![] })
} }
BuiltinFunction::Debug => {
interned_type!(Function { return_type: Type::Void, args: vec![Type::String] })
} }
BuiltinFunction::Mod => { };
interned_type!(Function {
return_type: Type::Int32,
args: vec![Type::Int32, Type::Int32]
})
} }
BuiltinFunction::Round | BuiltinFunction::Ceil | BuiltinFunction::Floor => {
interned_type!(Function { return_type: Type::Int32, args: vec![Type::Float32] }) declare_builtin_function_types!(
} GetWindowScaleFactor: () -> Type::UnitProduct(vec![(Unit::Phx, 1), (Unit::Px, -1)]),
BuiltinFunction::Sqrt | BuiltinFunction::Abs => { GetWindowDefaultFontSize: () -> Type::LogicalLength,
interned_type!(Function { return_type: Type::Float32, args: vec![Type::Float32] }) AnimationTick: () -> Type::Duration,
} Debug: (Type::String) -> Type::Void,
BuiltinFunction::Cos | BuiltinFunction::Sin | BuiltinFunction::Tan => { Mod: (Type::Int32, Type::Int32) -> Type::Int32,
interned_type!(Function { return_type: Type::Float32, args: vec![Type::Angle] }) Round: (Type::Float32) -> Type::Int32,
} Ceil: (Type::Float32) -> Type::Int32,
BuiltinFunction::ACos | BuiltinFunction::ASin | BuiltinFunction::ATan => { Floor: (Type::Float32) -> Type::Int32,
interned_type!(Function { return_type: Type::Angle, args: vec![Type::Float32] }) Sqrt: (Type::Float32) -> Type::Float32,
} Abs: (Type::Float32) -> Type::Float32,
BuiltinFunction::ATan2 => { Cos: (Type::Angle) -> Type::Float32,
interned_type!(Function { Sin: (Type::Angle) -> Type::Float32,
return_type: Type::Angle, Tan: (Type::Angle) -> Type::Float32,
args: vec![Type::Float32, Type::Float32] ACos: (Type::Float32) -> Type::Angle,
}) ASin: (Type::Float32) -> Type::Angle,
} ATan: (Type::Float32) -> Type::Angle,
BuiltinFunction::Log | BuiltinFunction::Pow => { ATan2: (Type::Float32, Type::Float32) -> Type::Angle,
interned_type!(Function { Log: (Type::Float32, Type::Float32) -> Type::Float32,
return_type: Type::Float32, Pow: (Type::Float32, Type::Float32) -> Type::Float32,
args: vec![Type::Float32, Type::Float32] SetFocusItem: (Type::ElementReference) -> Type::Void,
}) ClearFocusItem: (Type::ElementReference) -> Type::Void,
} ShowPopupWindow: (Type::ElementReference) -> Type::Void,
BuiltinFunction::SetFocusItem ClosePopupWindow: (Type::ElementReference) -> Type::Void,
| BuiltinFunction::ClearFocusItem ItemMemberFunction(..): (Type::ElementReference) -> Type::Void,
| BuiltinFunction::ShowPopupWindow SetSelectionOffsets: (Type::ElementReference, Type::Int32, Type::Int32) -> Type::Void,
| BuiltinFunction::ClosePopupWindow ItemFontMetrics: (Type::ElementReference) -> crate::typeregister::font_metrics_type(),
| BuiltinFunction::ItemMemberFunction(..) => { StringToFloat: (Type::String) -> Type::Float32,
interned_type!(Function { StringIsFloat: (Type::String) -> Type::Bool,
return_type: Type::Void, ImplicitLayoutInfo(..): (Type::ElementReference) -> crate::layout::layout_info_type(),
args: vec![Type::ElementReference] ColorRgbaStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {
})
}
BuiltinFunction::SetSelectionOffsets => interned_type!(Function {
return_type: Type::Void,
args: vec![Type::ElementReference, Type::Int32, Type::Int32],
}),
BuiltinFunction::ItemFontMetrics => interned_type!(Function {
return_type: crate::typeregister::font_metrics_type(),
args: vec![Type::ElementReference],
}),
BuiltinFunction::StringToFloat => {
interned_type!(Function { return_type: Type::Float32, args: vec![Type::String] })
}
BuiltinFunction::StringIsFloat => {
interned_type!(Function { return_type: Type::Bool, args: vec![Type::String] })
}
BuiltinFunction::ImplicitLayoutInfo(_) => interned_type!(Function {
return_type: crate::layout::layout_info_type(),
args: vec![Type::ElementReference],
}),
BuiltinFunction::ColorRgbaStruct => interned_type!(Function {
return_type: Type::Struct(Rc::new(Struct {
fields: IntoIterator::into_iter([ fields: IntoIterator::into_iter([
(SmolStr::new_static("red"), Type::Int32), (SmolStr::new_static("red"), Type::Int32),
(SmolStr::new_static("green"), Type::Int32), (SmolStr::new_static("green"), Type::Int32),
@ -203,10 +174,7 @@ impl BuiltinFunction {
node: None, node: None,
rust_attributes: None, rust_attributes: None,
})), })),
args: vec![Type::Color], ColorHsvaStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {
}),
BuiltinFunction::ColorHsvaStruct => interned_type!(Function {
return_type: Type::Struct(Rc::new(Struct {
fields: IntoIterator::into_iter([ fields: IntoIterator::into_iter([
(SmolStr::new_static("hue"), Type::Float32), (SmolStr::new_static("hue"), Type::Float32),
(SmolStr::new_static("saturation"), Type::Float32), (SmolStr::new_static("saturation"), Type::Float32),
@ -218,23 +186,12 @@ impl BuiltinFunction {
node: None, node: None,
rust_attributes: None, rust_attributes: None,
})), })),
args: vec![Type::Color], ColorBrighter: (Type::Brush, Type::Float32) -> Type::Brush,
}), ColorDarker: (Type::Brush, Type::Float32) -> Type::Brush,
BuiltinFunction::ColorBrighter ColorTransparentize: (Type::Brush, Type::Float32) -> Type::Brush,
| BuiltinFunction::ColorDarker ColorWithAlpha: (Type::Brush, Type::Float32) -> Type::Brush,
| BuiltinFunction::ColorTransparentize ColorMix: (Type::Color, Type::Color, Type::Float32) -> Type::Color,
| BuiltinFunction::ColorWithAlpha => { ImageSize: (Type::Image) -> Type::Struct(Rc::new(Struct {
interned_type!(Function {
return_type: Type::Brush,
args: vec![Type::Brush, Type::Float32]
})
}
BuiltinFunction::ColorMix => interned_type!(Function {
return_type: Type::Color,
args: vec![Type::Color, Type::Color, Type::Float32],
}),
BuiltinFunction::ImageSize => interned_type!(Function {
return_type: Type::Struct(Rc::new(Struct {
fields: IntoIterator::into_iter([ fields: IntoIterator::into_iter([
(SmolStr::new_static("width"), Type::Int32), (SmolStr::new_static("width"), Type::Int32),
(SmolStr::new_static("height"), Type::Int32), (SmolStr::new_static("height"), Type::Int32),
@ -244,84 +201,36 @@ impl BuiltinFunction {
node: None, node: None,
rust_attributes: None, rust_attributes: None,
})), })),
args: vec![Type::Image], ArrayLength: (Type::Model) -> Type::Int32,
}), Rgb: (Type::Int32, Type::Int32, Type::Int32, Type::Float32) -> Type::Color,
BuiltinFunction::ArrayLength => { Hsv: (Type::Float32, Type::Float32, Type::Float32, Type::Float32) -> Type::Color,
interned_type!(Function { return_type: Type::Int32, args: vec![Type::Model] }) ColorScheme: () -> Type::Enumeration(
}
BuiltinFunction::Rgb => interned_type!(Function {
return_type: Type::Color,
args: vec![Type::Int32, Type::Int32, Type::Int32, Type::Float32],
}),
BuiltinFunction::Hsv => interned_type!(Function {
return_type: Type::Color,
args: vec![Type::Float32, Type::Float32, Type::Float32, Type::Float32],
}),
BuiltinFunction::ColorScheme => interned_type!(Function {
return_type: Type::Enumeration(
crate::typeregister::BUILTIN.with(|e| e.enums.ColorScheme.clone()), crate::typeregister::BUILTIN.with(|e| e.enums.ColorScheme.clone()),
), ),
args: vec![], MonthDayCount: (Type::Int32, Type::Int32) -> Type::Int32,
}), MonthOffset: (Type::Int32, Type::Int32) -> Type::Int32,
BuiltinFunction::MonthDayCount | BuiltinFunction::MonthOffset => { FormatDate: (Type::String, Type::Int32, Type::Int32, Type::Int32) -> Type::String,
interned_type!(Function { TextInputFocused: () -> Type::Bool,
return_type: Type::Int32, DateNow: () -> Type::Array(Rc::new(Type::Int32)),
args: vec![Type::Int32, Type::Int32] ValidDate: (Type::String, Type::String) -> Type::Bool,
}) ParseDate: (Type::String, Type::String) -> Type::Array(Rc::new(Type::Int32)),
} SetTextInputFocused: (Type::Bool) -> Type::Void,
BuiltinFunction::FormatDate => interned_type!(Function { ItemAbsolutePosition: (Type::ElementReference) -> crate::typeregister::logical_point_type(),
return_type: Type::String, RegisterCustomFontByPath: (Type::String) -> Type::Void,
args: vec![Type::String, Type::Int32, Type::Int32, Type::Int32], RegisterCustomFontByMemory: (Type::Int32) -> Type::Void,
}), RegisterBitmapFont: (Type::Int32) -> Type::Void,
BuiltinFunction::TextInputFocused => {
interned_type!(Function { return_type: Type::Bool, args: vec![] })
}
BuiltinFunction::DateNow => {
interned_type!(Function {
return_type: Type::Array(Rc::new(Type::Int32)),
args: vec![]
})
}
BuiltinFunction::ValidDate => {
interned_type!(Function {
return_type: Type::Bool,
args: vec![Type::String, Type::String]
})
}
BuiltinFunction::ParseDate => interned_type!(Function {
return_type: Type::Array(Rc::new(Type::Int32)),
args: vec![Type::String, Type::String],
}),
BuiltinFunction::SetTextInputFocused => {
interned_type!(Function { return_type: Type::Void, args: vec![Type::Bool] })
}
BuiltinFunction::ItemAbsolutePosition => interned_type!(Function {
return_type: crate::typeregister::logical_point_type(),
args: vec![Type::ElementReference],
}),
BuiltinFunction::RegisterCustomFontByPath => {
interned_type!(Function { return_type: Type::Void, args: vec![Type::String] })
}
BuiltinFunction::RegisterCustomFontByMemory | BuiltinFunction::RegisterBitmapFont => {
interned_type!(Function { return_type: Type::Void, args: vec![Type::Int32] })
}
BuiltinFunction::Translate => interned_type!(Function {
return_type: Type::String,
// original, context, domain, args // original, context, domain, args
args: vec![ Translate: (Type::String, Type::String, Type::String, Type::Array(Type::String.into())) -> Type::String,
Type::String, Use24HourFormat: () -> Type::Bool,
Type::String, UpdateTimers: () -> Type::Void,
Type::String, );
Type::Array(Type::String.into()),
], impl BuiltinFunction {
}), pub fn ty(&self) -> Type {
BuiltinFunction::Use24HourFormat => { thread_local! {
interned_type!(Function { return_type: Type::Bool, args: vec![] }) static TYPES: BuiltinFunctionTypes = BuiltinFunctionTypes::new();
}
BuiltinFunction::UpdateTimers => {
interned_type!(Function { return_type: Type::Void, args: vec![] })
}
} }
TYPES.with(|types| types.ty(&self))
} }
/// It is const if the return value only depends on its argument and has no side effect /// It is const if the return value only depends on its argument and has no side effect