Skip to content

Instantly share code, notes, and snippets.

@eddyb eddyb/dom-thin.rs forked from jdm/gist:9900569
Last active Aug 29, 2015

Embed
What would you like to do?
// <core>
#[lang="vtable"]
struct Vtable<T, Sized? Trait>(&'static (unsafe fn(*mut T), uint, uint));
extern "rust-intrinsic" { fn get_vtable<T, Sized? Trait>() -> Vtable<T, Trait>; }
#[lang="has_vtable"]
trait HasVtable<T, Sized? Trait> {}
// </core>
#[repr(fixed, inline_vtable)]
trait Node: Any {
type V: HasVtable<Node, Self> = Vtable<Node, Self>;
vtable: V,
parent: Rc<Node>, first_child: Rc<Node>;
// TODO(eddyb) this can be made non-virtual using an associated
// const bitset of traits that the V vtable contains as a prefix.
fn as_element<'a>(&'a self) -> Option<&'a Element> { None }
}
impl Node {
fn as_text_node<'a>(&'a self) -> Option<&'a TextNode> {
self.downcast_ref::<TextNode>()
}
}
struct TextNode {
vtable: Vtable<Node, TextNode>,
parent: Rc<Node>, first_child: Rc<Node>,
...
}
impl Node for TextNode {}
#[repr(fixed, inline_vtable)]
trait Element: Node where Self::V: HasVtable<Element, Self> {
#[override_default]
type V = Vtable<Element, Self>;
attrs: HashMap<String, String>;
fn set_attribute(&self, key: &str, value: &str) {
self.before_set_attr(key, value);
//...update attrs...
self.after_set_attr(key, value);
}
fn before_set_attr(&self, key: &str, value: &str);
fn after_set_attr(&self, key: &str, value: &str);
#[override_default]
fn as_element<'a>(&'a self) -> Option<&'a Element> { Some(self) }
}
struct HTMLImageElement {
vtable: Vtable<Element, HTMLImageElement>,
parent: Rc<Node>, first_child: Rc<Node>,
attrs: HashMap<String, String>,
...
}
#[allow(override_default)]
impl Element for HTMLImageElement {
fn before_set_attr(&self, key: &str, value: &str) {
if key == "src" {
//..remove cached image with url `value`...
}
Element::default::before_set_attr(self, key, value);
}
}
struct HTMLVideoElement {
vtable: Vtable<Element, HTMLVideoElement>,
parent: Rc<Node>, first_child: Rc<Node>,
attrs: HashMap<String, String>,
cross_origin: bool,
...
}
#[allow(override_default)]
impl Element for HTMLVideoElement {
fn after_set_attr(&self, key: &str, value: &str) {
if key == "crossOrigin" {
self.cross_origin = value == "true";
}
Element::default::after_set_attr(self, key, value);
}
}
fn process_any_element(element: &Element) {
//...
}
let videoElement: Rc<HTMLVideoElement> = ...;
process_any_element(&*videoElement);
let node = &*videoElement.first_child;
let element = node.as_element();
match node.as_element() {
Some(element) => ...,
None => {
let text = node.as_text_node().unwrap();
...
}
}
struct Node {
shared_ptr<Node> parent;
shared_ptr<Node> first_child;
TextNode* as_text_node() { assert(/*sensible check*/); return (TextNode*)this; }
virtual Element* as_element() { return NULL; }
};
struct TextNode: public Node {};
struct Element: public Node {
map<string, string> attrs;
void set_attribute(const string& key, const string& value) {
before_set_attr(key, value);
//...update attrs...
after_set_attr(key, value);
}
virtual void before_set_attr(const string& key, const string& value);
virtual void after_set_attr(const string& key, const string& value);
virtual Element* as_element() { return this; }
};
struct HTMLImageElement: public Element {
virtual void before_set_attr(const string& key, const string& value) {
if(key == "src") {
//..remove cached image with url |value|...
}
Element::before_set_attr(key, value);
}
}
struct HTMLVideoElement: public Element {
bool cross_origin;
void after_set_attr(const string& key, const string& value) {
if(key == "crossOrigin") {
cross_origin = value == "true";
}
Element::after_set_attr(key, value);
}
}
void process_any_element(Element* element) {
//...
}
shared_ptr<HTMLVideoElement> videoElement = ...;
process_any_element(videoElement);
shared_ptr<Node> node = videoElement->first_child;
shared_ptr<Element> element = node->as_element();
if(!element) {
shared_ptr<TextNode> text = node->as_text_node();
}
#[repr(fixed)]
trait Node: Any {
parent: Rc<Node>, first_child: Rc<Node>;
fn as_element<'a>(&'a self) -> Option<&'a Element> { None }
}
impl Node {
fn as_text_node<'a>(&'a self) -> Option<&'a TextNode> {
self.downcast_ref::<TextNode>()
}
}
struct TextNode { parent: Rc<Node>, first_child: Rc<Node>, ... }
impl Node for TextNode {}
#[repr(fixed)]
trait Element: Node {
attrs: HashMap<String, String>;
fn set_attribute(&self, key: &str, value: &str) {
self.before_set_attr(key, value);
//...update attrs...
self.after_set_attr(key, value);
}
fn before_set_attr(&self, key: &str, value: &str);
fn after_set_attr(&self, key: &str, value: &str);
#[override_default]
fn as_element<'a>(&'a self) -> Option<&'a Element> { Some(self) }
}
struct HTMLImageElement {
parent: Rc<Node>, first_child: Rc<Node>,
attrs: HashMap<String, String>,
...
}
#[allow(override_default)]
impl Element for HTMLImageElement {
fn before_set_attr(&self, key: &str, value: &str) {
if key == "src" {
//..remove cached image with url `value`...
}
Element::default::before_set_attr(self, key, value);
}
}
struct HTMLVideoElement {
parent: Rc<Node>, first_child: Rc<Node>,
attrs: HashMap<String, String>,
cross_origin: bool,
...
}
#[allow(override_default)]
impl Element for HTMLVideoElement {
fn after_set_attr(&self, key: &str, value: &str) {
if key == "crossOrigin" {
self.cross_origin = value == "true";
}
Element::default::after_set_attr(self, key, value);
}
}
fn process_any_element(element: &Element) {
//...
}
let videoElement: Rc<HTMLVideoElement> = ...;
process_any_element(&*videoElement);
let node = &*videoElement.first_child;
let element = node.as_element();
match node.as_element() {
Some(element) => ...,
None => {
let text = node.as_text_node().unwrap();
...
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.