mirror of
https://github.com/lexmount/moli.git
synced 2026-10-30 08:07:38 +00:00
perf(webapi): generate static accessor function names
Move getter/setter name formatting into the derive macro and reuse the getter name suffix as the property key, avoiding a third stored name. Keep shared installation and V8 callback mappings. Cover static names and Unicode property keys in the existing tests.
This commit is contained in:
@@ -582,6 +582,15 @@ fn static_template_accessor(
|
||||
let Some(name) = webapi_field_name_literal(attrs.name.as_ref()) else {
|
||||
return Ok(None);
|
||||
};
|
||||
let getter_name = LitStr::new(&format!("get {}", name.value()), name.span());
|
||||
let setter_name = LitStr::new(
|
||||
&if attrs.setter.is_some() {
|
||||
format!("set {}", name.value())
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
name.span(),
|
||||
);
|
||||
let getter = attrs.getter.as_ref().ok_or_else(|| {
|
||||
Error::new(
|
||||
field.span(),
|
||||
@@ -604,7 +613,8 @@ fn static_template_accessor(
|
||||
let setter_receiver = receiver.checks_setter();
|
||||
Ok(Some(quote! {
|
||||
::moli_webapi_declare::__private::FunctionTemplateAccessor {
|
||||
name: #name,
|
||||
getter_name: #getter_name,
|
||||
setter_name: #setter_name,
|
||||
getter: #getter,
|
||||
setter: #setter,
|
||||
enumerable: #enumerable,
|
||||
@@ -2254,6 +2264,8 @@ mod tests {
|
||||
struct SampleTemplate {
|
||||
#[webapi(accessor_property, getter = sample_getter)]
|
||||
value: (),
|
||||
#[webapi(accessor_property = "mutable-Δ", getter = sample_getter, setter = sample_setter)]
|
||||
mutable: (),
|
||||
#[webapi(accessor_property = "named", getter = sample_getter, setter = sample_setter, data = getter_data, setter_data = setter_data, dont_delete)]
|
||||
named: (),
|
||||
}
|
||||
@@ -2262,6 +2274,10 @@ mod tests {
|
||||
.expect("template accessors should expand")
|
||||
.to_string();
|
||||
assert!(tokens.contains("FunctionTemplateAccessor"));
|
||||
assert!(tokens.contains("getter_name : \"get value\""));
|
||||
assert!(tokens.contains("setter_name : \"\""));
|
||||
assert!(tokens.contains("getter_name : \"get mutable-Δ\""));
|
||||
assert!(tokens.contains("setter_name : \"set mutable-Δ\""));
|
||||
assert!(tokens.contains("String :: new (scope , \"get named\")"));
|
||||
assert!(tokens.contains("String :: new (scope , \"set named\")"));
|
||||
assert!(tokens.contains("install_function_template_accessor"));
|
||||
|
||||
@@ -171,9 +171,12 @@ pub fn install_function_template_methods<'s>(
|
||||
|
||||
/// Static metadata for a string-named accessor without callback data.
|
||||
/// Mappings preserve constant tables while using V8's original call-time path.
|
||||
/// The derive prefixes getter names with "get "; the suffix is the property key.
|
||||
#[doc(hidden)]
|
||||
pub struct FunctionTemplateAccessor {
|
||||
pub name: &'static str,
|
||||
pub getter_name: &'static str,
|
||||
/// Empty when no setter is declared.
|
||||
pub setter_name: &'static str,
|
||||
pub getter: fn() -> v8::FunctionCallback,
|
||||
pub setter: Option<fn() -> v8::FunctionCallback>,
|
||||
pub enumerable: bool,
|
||||
@@ -192,7 +195,7 @@ pub fn install_function_template_accessors<'s>(
|
||||
accessors: &[FunctionTemplateAccessor],
|
||||
) {
|
||||
for accessor in accessors {
|
||||
let key = v8str(scope, accessor.name);
|
||||
let key = v8str(scope, &accessor.getter_name["get ".len()..]);
|
||||
let mut attributes = v8::PropertyAttribute::NONE;
|
||||
if !accessor.enumerable {
|
||||
attributes = attributes | v8::PropertyAttribute::DONT_ENUM;
|
||||
@@ -207,14 +210,14 @@ pub fn install_function_template_accessors<'s>(
|
||||
callback: (accessor.getter)(),
|
||||
length: 0,
|
||||
data: None,
|
||||
class_name: v8::String::new(scope, &format!("get {}", accessor.name)),
|
||||
class_name: v8::String::new(scope, accessor.getter_name),
|
||||
receiver_access_check: accessor.getter_receiver_access_check,
|
||||
};
|
||||
let setter = accessor.setter.map(|mapping| FunctionTemplateMember {
|
||||
callback: mapping(),
|
||||
length: 1,
|
||||
data: None,
|
||||
class_name: v8::String::new(scope, &format!("set {}", accessor.name)),
|
||||
class_name: v8::String::new(scope, accessor.setter_name),
|
||||
receiver_access_check: accessor.setter_receiver_access_check,
|
||||
});
|
||||
install_function_template_accessor(scope, target, key.into(), getter, setter, attributes);
|
||||
|
||||
@@ -439,7 +439,7 @@ const DYNAMIC_ATTRIBUTE_NAME: &str = "runtimeAttribute";
|
||||
struct AttributeMetadataTemplateDeclaration {
|
||||
#[webapi(accessor_property, getter = sample_receiver_getter)]
|
||||
implicit_name: (),
|
||||
#[webapi(accessor_property = "explicit-name", getter = sample_receiver_getter)]
|
||||
#[webapi(accessor_property = "explicit-name-Δ", getter = sample_receiver_getter)]
|
||||
explicit: (),
|
||||
#[webapi(native_data_property, getter = sample_native_holder_getter)]
|
||||
native_holder: (),
|
||||
@@ -466,7 +466,7 @@ fn prototype_attribute_metadata_tracks_static_attribute_keys() {
|
||||
let attributes = AttributeMetadataTemplateDeclaration::PROTOTYPE_ATTRIBUTE_NAMES;
|
||||
assert_eq!(
|
||||
attributes,
|
||||
["implicitName", "explicit-name", "nativeHolder"]
|
||||
["implicitName", "explicit-name-Δ", "nativeHolder"]
|
||||
);
|
||||
for attribute in attributes {
|
||||
assert!(
|
||||
@@ -477,6 +477,17 @@ fn prototype_attribute_metadata_tracks_static_attribute_keys() {
|
||||
.boolean_value(scope)
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
run_script(
|
||||
scope,
|
||||
r#"['implicitName', 'explicit-name-Δ'].every(key => {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(AttributeMetadata.prototype, key);
|
||||
return descriptor.get.name === `get ${key}`
|
||||
&& descriptor.get.length === 0 && descriptor.set === undefined;
|
||||
})"#
|
||||
)
|
||||
.boolean_value(scope)
|
||||
);
|
||||
assert!(
|
||||
run_script(
|
||||
scope,
|
||||
|
||||
Reference in New Issue
Block a user