For those who just want to see a before/after summary, here's an example.
BEFORE: we have to handwrite conversion routines for each downcast or
upcast we want to use. Furthermore, we have the ugly
AbstractDocument/AbstractNode/AbstractEvent/AbstractEventTarget types,
in addition to all of the concrete @mut SomeDOMType that are scattered
everywhere.
impl AbstractNode<ScriptView> {
/// Allow consumers to upcast from derived classes.
pub fn from_document(doc: AbstractDocument) -> AbstractNode<View> {
unsafe {
cast::transmute(doc)
}
}
pub fn from_eventtarget(target: AbstractEventTarget) ->
tractNode<View> {
assert!(target.is_node());
unsafe {
cast::transmute(target)
}
}
}
788 let doctarget = AbstractEventTarget::from_document(document);
789 let wintarget = AbstractEventTarget::from_window(window);
790 window.eventtarget.dispatch_event_with_target(wintarget,
Some(doctarget), event);
307 if child.is_element() {
308 do child.with_imm_element |elem| {
309 if callback(elem) {
310 elements.push(child);
311 }
312 }
313 }
AFTER all casting methods are automatically generated; all that's left
is writing the is_foo method and ensuring that we can tell the concrete
type of a DOM object based on the root type in an inheritance chain:
impl UIEventDerived for Event {
fn is_uievent(&self) -> bool {
self.type_id == UIEventTypeId
}
}
let doctarget = EventTargetCast::from(document);
let wintarget = EventTargetCast::from(window);
window.eventtarget.dispatch_event_with_target(wintarget,
Some(doctarget), event);
if child.is_element() {
let elem = ElementCast::to(child);
if callback(elem) {
elements.push(elem);
}
}
In my mind, the biggest improvement here is that we can actually have
lists of JSManaged<Element>, whereas before we could only store
~[AbstractNode] with the handwave-y guarantee that all of the nodes
should also be elements. I also find the new checked casts much nicer to
read (and yes, the downcasts assert at runtime if the value passed is
not an instance of the desired type).
Cheers,
Josh
On 12/03/2013 03:07 AM, Josh Matthews wrote:
Ms2ger and I have been working on this on and off, and the Event
hierarchy is looking very nice so far:
https://github.com/jdm/servo/commits/jsmanaged . It even builds and
passes tests, so we should be able to continue converting this
piece-by-piece. There is an absolute minimum amount of boilerplate
required now, which is lovely.
Cheers,
Josh
On 11/28/2013 10:54 AM, Josh Matthews wrote:
I've finally got a sketch of my plans to remove all of the @mut
annotations from Servo's DOM. You can see it at
https://gist.github.com/jdm/7693770, but here's the breakdown of the
improvements:
* no more AbstractNode (\o/) - we can actually use JSManaged<Element>
when we want to refer to something derived from Element now.
* actually fulfils the contract that the SpiderMonkey GC owns the sole
reference
* no need to add as_foo methods for downcasting
Breaking it down further, one of the biggest changes is in the
implementation of downcasting and upcasting. Upcasting a JSManaged<Foo>
to a JSManaged<Bar> is a statically-checked operation that should be
free at runtime. This is enforced by a series of empty traits that each
derived class much implement (ie. see EventTargetBase), such that any
value passed to Bar::from() must be a type that implements BarBase. In a
similar fashion, downcasting is also statically-checked (does the cast
even make sense?), before performing a dynamic assertion (is this base
class actually an instance of the derived type?). Therefore, when
calling Foo::to(), the value passed must implement the FooDerived trait
with an appropriate boolean is_foo method implemented.
These casting changes may not look like a big improvement at first, but
the important consideration is the the upcasting traits can be
automatically generated completely from WebIDL definitions, so that
boilerplate should be essentially free. For downcasting, each type that
is on an inheritance chain will need to implement a single trait with a
single boolean method that performs the required dynamic check; all
other boilerplate can also be generated from WebIDL definitions, and is
therefore essentially free.
I welcome feedback about this sketch. For a quick look at how it can be
used by consumers, see main() in jsgc.rs.
Cheers,
Josh
_______________________________________________
dev-servo mailing list
dev-servo@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-servo