diff options
author | Josh Matthews <josh@joshmatthews.net> | 2024-11-24 13:15:50 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-24 18:15:50 +0000 |
commit | c60e4afbee1bc70bb9fe36ad138c6aa5bb98414d (patch) | |
tree | 42ae102432c2b49e92400fd8415d7a46772a2811 /components/script/dom/bindings/codegen | |
parent | 3faed9b9212fee1f0ff9be5f7cfb5e24c5b84b91 (diff) | |
download | servo-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.conf | 46 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 79 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/Configuration.py | 12 |
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) |