| // <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