aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/codegen
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2024-11-24 13:15:50 -0500
committerGitHub <noreply@github.com>2024-11-24 18:15:50 +0000
commitc60e4afbee1bc70bb9fe36ad138c6aa5bb98414d (patch)
tree42ae102432c2b49e92400fd8415d7a46772a2811 /components/script/dom/bindings/codegen
parent3faed9b9212fee1f0ff9be5f7cfb5e24c5b84b91 (diff)
downloadservo-c60e4afbee1bc70bb9fe36ad138c6aa5bb98414d.tar.gz
servo-c60e4afbee1bc70bb9fe36ad138c6aa5bb98414d.zip
Support custom derives for generated types (#34356)
* script: Derive more Default implementations for dictionaries. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Support arbitrary derives on generated enums. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Support arbitrary derives for generated dictionaries. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Support arbitrary derives for generated unions. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Derive more impls for generated dicts and unions. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Implement FromStr for generated enums. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Fix clippy. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * crown: Allow returning unrooted values from Default::default. Signed-off-by: Josh Matthews <josh@joshmatthews.net> --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
Diffstat (limited to 'components/script/dom/bindings/codegen')
-rw-r--r--components/script/dom/bindings/codegen/Bindings.conf46
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py79
-rw-r--r--components/script/dom/bindings/codegen/Configuration.py12
3 files changed, 123 insertions, 14 deletions
diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf
index 48d9392465f..a1f3de7e46a 100644
--- a/components/script/dom/bindings/codegen/Bindings.conf
+++ b/components/script/dom/bindings/codegen/Bindings.conf
@@ -527,3 +527,49 @@ DOMInterfaces = {
},
}
+
+Dictionaries = {
+'GPUCanvasConfiguration': {
+ 'derives': ['Clone']
+},
+
+'GPUExtent3DDict': {
+ 'derives': ["MallocSizeOf"],
+},
+
+'GPUObjectDescriptorBase': {
+ 'derives': ['MallocSizeOf']
+},
+
+'GPUTextureDescriptor': {
+ 'derives': ["MallocSizeOf"],
+},
+
+'HeadersInit': {
+ 'derives': ["Clone"],
+},
+}
+
+Enums = {
+'GPUFeatureName': {
+ 'derives': ['Hash', 'Eq']
+}
+}
+
+Unions = {
+'ByteStringSequenceSequenceOrByteStringByteStringRecord': {
+ 'derives': ['Clone']
+},
+
+'HTMLCanvasElementOrOffscreenCanvas': {
+ 'derives': ['Clone', 'MallocSizeOf']
+},
+
+'RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict': {
+ 'derives': ['MallocSizeOf']
+},
+
+'StringOrUnsignedLong': {
+ 'derives': ['Clone'],
+},
+} \ No newline at end of file
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 6ac9ae1d5d9..83f183283ec 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -2649,7 +2649,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
if name not in unionStructs:
provider = descriptor or config.getDescriptorProvider()
unionStructs[name] = CGList([
- CGUnionStruct(t, provider),
+ CGUnionStruct(t, provider, config),
CGUnionConversionStruct(t, provider)
])
@@ -4865,14 +4865,18 @@ def getEnumValueName(value):
class CGEnum(CGThing):
- def __init__(self, enum):
+ def __init__(self, enum, config):
CGThing.__init__(self)
ident = enum.identifier.name
enums = ",\n ".join(map(getEnumValueName, list(enum.values())))
+ derives = ["Copy", "Clone", "Debug", "JSTraceable", "MallocSizeOf", "PartialEq"]
+ enum_config = config.getEnumConfig(ident)
+ extra_derives = enum_config.get('derives', [])
+ derives = ', '.join(derives + extra_derives)
decl = f"""
#[repr(usize)]
-#[derive(Copy, Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)]
+#[derive({derives})]
pub enum {ident} {{
{enums}
}}
@@ -4907,6 +4911,18 @@ impl Default for super::{ident} {{
}}
}}
+impl std::str::FromStr for super::{ident} {{
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {{
+ pairs
+ .iter()
+ .find(|&&(key, _)| s == key)
+ .map(|&(_, ev)| ev)
+ .ok_or(())
+ }}
+}}
+
impl ToJSValConvertible for super::{ident} {{
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {{
pairs[*self as usize].0.to_jsval(cx, rval);
@@ -5037,12 +5053,13 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
class CGUnionStruct(CGThing):
- def __init__(self, type, descriptorProvider):
+ def __init__(self, type, descriptorProvider, config):
assert not type.nullable()
assert not type.hasNullableType
CGThing.__init__(self)
self.type = type
+ self.derives = config.getUnionConfig(str(type)).get('derives', [])
self.descriptorProvider = descriptorProvider
def membersNeedTracing(self):
@@ -5071,8 +5088,9 @@ class CGUnionStruct(CGThing):
]
joinedEnumValues = "\n".join(enumValues)
joinedEnumConversions = "\n".join(enumConversions)
+ derives = ["JSTraceable"] + self.derives
return f"""
-#[derive(JSTraceable)]
+#[derive({", ".join(derives)})]
pub enum {self.type} {{
{joinedEnumValues}
}}
@@ -6879,9 +6897,10 @@ class CGNonNamespacedEnum(CGThing):
class CGDictionary(CGThing):
- def __init__(self, dictionary, descriptorProvider):
+ def __init__(self, dictionary, descriptorProvider, config):
self.dictionary = dictionary
- if all(CGDictionary(d, descriptorProvider).generatable for
+ self.derives = config.getDictConfig(dictionary.identifier.name).get('derives', [])
+ if all(CGDictionary(d, descriptorProvider, config).generatable for
d in CGDictionary.getDictionaryDependencies(dictionary)):
self.generatable = True
else:
@@ -6915,12 +6934,40 @@ class CGDictionary(CGThing):
memberDecls = [f" pub {self.makeMemberName(m[0].identifier.name)}: {self.getMemberType(m)},"
for m in self.memberInfo]
- derive = ["JSTraceable"]
+ derive = ["JSTraceable"] + self.derives
+ default = ""
mustRoot = ""
if self.membersNeedTracing():
mustRoot = "#[crown::unrooted_must_root_lint::must_root]\n"
- if not self.hasRequiredFields(self.dictionary):
- derive += ["Default"]
+
+ # We can't unconditionally derive Default here, because union types can have unique
+ # default values provided for each usage. Instead, whenever possible we re-use the empty()
+ # method that is generated.
+ if not self.hasRequiredFields(self.dictionary):
+ if d.parent:
+ inheritanceDefault = " parent: Default::default(),\n"
+ else:
+ inheritanceDefault = ""
+ if not self.membersNeedTracing():
+ impl = " Self::empty()\n"
+ else:
+ memberDefaults = [f" {self.makeMemberName(m[0].identifier.name)}: Default::default(),"
+ for m in self.memberInfo]
+ joinedDefaults = '\n'.join(memberDefaults)
+ impl = (
+ " Self {\n"
+ f" {inheritanceDefault}{joinedDefaults}"
+ " }\n"
+ )
+
+ default = (
+ f"impl Default for {self.makeClassName(d)} {{\n"
+ " fn default() -> Self {\n"
+ f"{impl}"
+ " }\n"
+ "}\n"
+ )
+
joinedMemberDecls = '\n'.join(memberDecls)
return (
f"#[derive({', '.join(derive)})]\n"
@@ -6928,7 +6975,8 @@ class CGDictionary(CGThing):
f"pub struct {self.makeClassName(d)} {{\n"
f"{inheritance}"
f"{joinedMemberDecls}\n"
- "}"
+ "}\n"
+ f"{default}"
)
def impl(self):
@@ -7227,7 +7275,7 @@ class CGBindingRoot(CGThing):
return
# Do codegen for all the enums.
- cgthings = [CGEnum(e) for e in enums]
+ cgthings = [CGEnum(e, config) for e in enums]
# Do codegen for all the typedefs
for t in typedefs:
@@ -7244,7 +7292,7 @@ class CGBindingRoot(CGThing):
cgthings.append(CGGeneric(typeDefinition))
# Do codegen for all the dictionaries.
- cgthings.extend([CGDictionary(d, config.getDescriptorProvider())
+ cgthings.extend([CGDictionary(d, config.getDescriptorProvider(), config)
for d in dictionaries])
# Do codegen for all the callbacks.
@@ -8145,7 +8193,10 @@ class GlobalGenRoots():
descriptors = (set(toBindingModuleFile(d.name) for d in descriptors if d.maybeGetSuperModule() is None)
| set(leafModule(d) for d in config.callbacks)
| set(leafModule(d) for d in config.getDictionaries()))
- curr = CGList([CGGeneric(f"pub mod {name};\n") for name in sorted(descriptors)])
+ curr = CGList([CGGeneric(
+ "#[allow(clippy::derivable_impls)]\n"
+ f"pub mod {name};\n"
+ ) for name in sorted(descriptors)])
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr
diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py
index 2f067c39256..b887fe91931 100644
--- a/components/script/dom/bindings/codegen/Configuration.py
+++ b/components/script/dom/bindings/codegen/Configuration.py
@@ -18,6 +18,9 @@ class Configuration:
glbl = {}
exec(compile(open(filename).read(), filename, 'exec'), glbl)
config = glbl['DOMInterfaces']
+ self.enumConfig = glbl['Enums']
+ self.dictConfig = glbl['Dictionaries']
+ self.unionConfig = glbl['Unions']
# Build descriptors for all the interfaces we have in the parse data.
# This allows callers to specify a subset of interfaces by filtering
@@ -110,6 +113,9 @@ class Configuration:
def getEnums(self, webIDLFile):
return [e for e in self.enums if e.filename == webIDLFile]
+ def getEnumConfig(self, name):
+ return self.enumConfig.get(name, {})
+
def getTypedefs(self, webIDLFile):
return [e for e in self.typedefs if e.filename == webIDLFile]
@@ -121,9 +127,15 @@ class Configuration:
return [x for x in items if x.filename == webIDLFile]
+ def getUnionConfig(self, name):
+ return self.unionConfig.get(name, {})
+
def getDictionaries(self, webIDLFile=""):
return self._filterForFile(self.dictionaries, webIDLFile=webIDLFile)
+ def getDictConfig(self, name):
+ return self.dictConfig.get(name, {})
+
def getCallbacks(self, webIDLFile=""):
return self._filterForFile(self.callbacks, webIDLFile=webIDLFile)