Assert that DOM structs have the correct first field

DOM structs embed their parent type as their first field. This
introduces a `.parent()` method to the DOM struct that returns its first
field, and codegens a type assert that ensures that `.parent()` returns
the parent struct.

This generates:

On `#[dom_struct]`:

```rust
impl HasParent for Type {
    type Parent = ParentType;
    fn as_parent(&self) -> ParentType {
        &self.first_field
    }
}
```

In the codegen files:

```rust
impl Type {
    fn __assert_parent_type(&self) {
        let _: &ParentType = self.as_parent();
    }
}
````
This commit is contained in:
Manish Goregaokar 2018-06-29 10:34:09 -07:00
parent e2fca1b228
commit ad198993b1
6 changed files with 109 additions and 9 deletions

View file

@ -2116,6 +2116,10 @@ class CGDOMJSClass(CGThing):
self.descriptor = descriptor
def define(self):
parentName = self.descriptor.getParentName()
if not parentName:
parentName = "::dom::bindings::reflector::Reflector"
args = {
"domClass": DOMClass(self.descriptor),
"enumerateHook": "None",
@ -2161,7 +2165,51 @@ static Class: DOMJSClass = DOMJSClass {
reserved: [0 as *mut _; 3],
},
dom_class: %(domClass)s
};""" % args
};
""" % args
class CGAssertInheritance(CGThing):
"""
Generate a type assertion for inheritance
"""
def __init__(self, descriptor):
CGThing.__init__(self)
self.descriptor = descriptor
def define(self):
parent = self.descriptor.interface.parent
parentName = ""
if parent:
parentName = parent.identifier.name
else:
parentName = "::dom::bindings::reflector::Reflector"
selfName = self.descriptor.interface.identifier.name
if selfName == "PaintRenderingContext2D":
# PaintRenderingContext2D embeds a CanvasRenderingContext2D
# instead of a Reflector as an optimization,
# but this is fine since CanvasRenderingContext2D
# also has a reflector
#
# FIXME *RenderingContext2D should use Inline
parentName = "::dom::canvasrenderingcontext2d::CanvasRenderingContext2D"
args = {
"parentName": parentName,
"selfName": selfName,
}
return """\
impl %(selfName)s {
fn __assert_parent_type(&self) {
use dom::bindings::inheritance::HasParent;
// If this type assertion fails, make sure the first field of your
// DOM struct is of the correct type -- it must be the parent class.
let _: &%(parentName)s = self.as_parent();
}
}
""" % args
def str_to_const_array(s):
@ -6011,6 +6059,8 @@ class CGDescriptor(CGThing):
pass
else:
cgThings.append(CGDOMJSClass(descriptor))
if not descriptor.interface.isIteratorInterface():
cgThings.append(CGAssertInheritance(descriptor))
pass
if descriptor.isGlobal():