Skip to content

Instantly share code, notes, and snippets.

@jdm
Created November 28, 2013 15:33
Show Gist options
  • Save jdm/7693770 to your computer and use it in GitHub Desktop.
Save jdm/7693770 to your computer and use it in GitHub Desktop.
use node::{DocumentTypeId, Node, NodeBase};
use jsmanaged::JSManaged;
use super::{Reflectable, Reflector};
use eventtarget::{EventTarget, EventTargetBase, NodeTargetTypeId};
pub trait DocumentDerived { fn is_document(&self) -> bool; }
pub trait DocumentBase : NodeBase {}
impl EventTargetBase for Document {}
impl NodeBase for Document {}
impl DocumentBase for Document {}
pub struct Document {
node: Node,
title: ~str
}
impl DocumentDerived for EventTarget {
fn is_document(&self) -> bool {
self.type_id == NodeTargetTypeId(DocumentTypeId)
}
}
impl Document {
pub fn new() -> JSManaged<Document> {
let doc = ~Document {
node: Node::new_inherited(DocumentTypeId),
title: ~""
};
JSManaged::new(doc)
}
pub fn title(&self) -> ~str {
self.title.clone()
}
pub fn set_title(&mut self, title: ~str) {
self.title = title;
}
}
impl Document {
pub fn from<T: DocumentBase>(derived: JSManaged<T>) -> JSManaged<Document> {
derived.transmute()
}
pub fn to<T: DocumentDerived>(base: JSManaged<T>) -> JSManaged<Document> {
assert!(base.val().is_document());
base.transmute()
}
}
impl Reflectable for Document {
fn reflector<'a> (&'a self) -> &'a Reflector {
self.node.reflector()
}
}
use eventtarget::{EventTarget, EventTargetBase, NodeTargetTypeId};
use node::{NodeBase, Node, ElementNodeTypeId};
use htmlelement::HTMLElementTypeId;
use jsmanaged::JSManaged;
use super::{Reflectable, Reflector};
pub trait ElementDerived { fn is_element(&self) -> bool; }
pub trait ElementBase : NodeBase {}
impl ElementDerived for EventTarget {
fn is_element(&self) -> bool {
match self.type_id {
NodeTargetTypeId(ElementNodeTypeId(_)) => true,
_ => false
}
}
}
impl EventTargetBase for Element {}
impl NodeBase for Element {}
impl ElementBase for Element {}
#[deriving(Eq)]
pub enum ElementTypeId {
HTMLElementId(HTMLElementTypeId),
}
struct Element {
node: Node
}
impl Element {
pub fn to<T: ElementDerived>(base: JSManaged<T>) -> JSManaged<Element> {
assert!(base.val().is_element());
base.transmute()
}
}
impl Reflectable for Element {
fn reflector<'a> (&'a self) -> &'a Reflector {
self.node.reflector()
}
}
use node::NodeTypeId;
use super::{Reflectable, Reflector};
use jsmanaged::JSManaged;
#[deriving(Eq)]
pub enum EventTargetTypeId {
NodeTargetTypeId(NodeTypeId),
WindowTargetTypeId
}
pub trait EventTargetBase {}
impl EventTargetBase for EventTarget {}
struct EventTarget {
reflector_: int,
type_id: EventTargetTypeId
}
impl EventTarget {
pub fn new_inherited(type_id: EventTargetTypeId) -> EventTarget {
EventTarget {
reflector_: 0,
type_id: type_id
}
}
pub fn from<T: EventTargetBase>(derived: JSManaged<T>) -> JSManaged<EventTarget> {
derived.transmute()
}
}
impl Reflectable for EventTarget {
fn reflector<'a> (&'a self) -> &'a Reflector {
&self.reflector_
}
}
use super::{Reflectable, Reflector};
use element::{Element, ElementBase, HTMLElementId};
use eventtarget::{EventTargetBase, EventTarget, NodeTargetTypeId};
use node::{NodeBase, ElementNodeTypeId};
pub trait HTMLElementDerived { fn is_htmlelement(&self) -> bool; }
pub trait HTMLElementBase : ElementBase {}
impl HTMLElementDerived for EventTarget {
fn is_htmlelement(&self) -> bool {
match self.type_id {
NodeTargetTypeId(ElementNodeTypeId(HTMLElementId(_))) => true,
_ => false
}
}
}
impl EventTargetBase for HTMLElement {}
impl NodeBase for HTMLElement {}
impl ElementBase for HTMLElement {}
impl HTMLElementBase for HTMLElement {}
#[deriving(Eq)]
pub enum HTMLElementTypeId {
VideoElementId,
UnknownElementId,
}
pub struct HTMLElement {
element: Element
}
impl Reflectable for HTMLElement {
fn reflector<'a> (&'a self) -> &'a Reflector {
self.element.reflector()
}
}
#[feature(macro_rules)];
#[macro_escape];
use self::window::Window;
use self::eventtarget::EventTarget;
use self::node::Node;
use self::document::Document;
pub trait Reflectable {
fn reflector<'a> (&'a self) -> &'a Reflector;
}
macro_rules! delegate_parent(
($tr: ident, $ty: ident, $name: ident, $field: ident) => (
impl $tr for $ty {
fn $name(&self) -> bool {
self.$field.$name()
}
}
)
)
type Reflector = int;
mod document;
mod element;
mod eventtarget;
mod node;
mod htmlelement;
mod window;
mod jsmanaged;
fn main() {
// Type::from is a statically-checked upcast
// Type::to is a statically+dynamically-checked downcast
let mut doc = Document::new();
doc.mut_val().set_title(~"title!");
println(doc.val().title());
let doc_node = Node::from(doc); // ok!
println!("{:?}", doc_node.val().eventtarget.reflector_);
let _doc_target = EventTarget::from(doc); // ok!
let _doc_target2 = EventTarget::from(doc_node); // ok!
let _win = Window::new(doc);
//let _elem = Element::to(doc_node); // error: runtime failure
//let _elem = Element::to(_doc_target); // error: runtime failure
let _node = Node::to(_doc_target); // ok!
//let _node = Document::from(_win); //error!
//let _node = Node::to(_win); //error!
}
use std::unstable::raw::Box;
use std::cast;
use super::Reflectable;
pub struct JSManaged<T> {
ptr: *mut Box<T>
}
impl<T: Reflectable> JSManaged<T> {
pub fn new(obj: ~T) -> JSManaged<T> {
JSManaged {
ptr: unsafe { cast::transmute(obj) }
}
}
}
impl<T> JSManaged<T> {
pub fn val<'a>(&'a self) -> &'a T {
unsafe {
&(*self.ptr).data
}
}
pub fn mut_val<'a>(&'a mut self) -> &'a mut T {
unsafe {
&mut (*self.ptr).data
}
}
}
impl<From, To> JSManaged<From> {
pub fn transmute(self) -> JSManaged<To> {
unsafe {
cast::transmute(self)
}
}
}
use document::DocumentDerived;
use eventtarget::{EventTargetBase, EventTarget, NodeTargetTypeId, WindowTargetTypeId};
use element::{ElementTypeId, ElementDerived};
use htmlelement::HTMLElementDerived;
use jsmanaged::JSManaged;
use super::{Reflectable, Reflector};
#[deriving(Eq)]
pub enum NodeTypeId {
DocumentTypeId,
ElementNodeTypeId(ElementTypeId)
}
pub trait NodeDerived { fn is_node(&self) -> bool; }
pub trait NodeBase : EventTargetBase {}
impl EventTargetBase for Node {}
impl NodeBase for Node {}
delegate_parent!(HTMLElementDerived, Node, is_htmlelement, eventtarget)
delegate_parent!(ElementDerived, Node, is_element, eventtarget)
delegate_parent!(DocumentDerived, Node, is_document, eventtarget)
impl NodeDerived for EventTarget {
fn is_node(&self) -> bool {
match self.type_id {
NodeTargetTypeId(_) => true,
WindowTargetTypeId => false
}
}
}
pub struct Node {
eventtarget: EventTarget,
first_child: Option<JSManaged<Node>>
}
impl Node {
pub fn new_inherited(type_id: NodeTypeId) -> Node {
Node {
eventtarget: EventTarget::new_inherited(NodeTargetTypeId(type_id)),
first_child: None
}
}
pub fn type_id(&self) -> NodeTypeId {
match self.eventtarget.type_id {
NodeTargetTypeId(id) => id,
_ => unreachable!()
}
}
pub fn GetFirstChild(&self) -> Option<JSManaged<Node>> {
self.first_child
}
pub fn from<T: NodeBase>(derived: JSManaged<T>) -> JSManaged<Node> {
derived.transmute()
}
pub fn to<T: NodeDerived>(base: JSManaged<T>) -> JSManaged<Node> {
assert!(base.val().is_node());
base.transmute()
}
}
impl Reflectable for Node {
fn reflector<'a> (&'a self) -> &'a Reflector {
self.eventtarget.reflector()
}
}
use eventtarget::{WindowTargetTypeId, EventTargetBase, EventTarget};
use jsmanaged::JSManaged;
use super::{Reflectable, Reflector};
use document::Document;
pub trait WindowDerived { fn is_window(&self) -> bool; }
impl WindowDerived for EventTarget {
fn is_window(&self) -> bool {
self.type_id == WindowTargetTypeId
}
}
impl EventTargetBase for Window {}
pub struct Window {
eventtarget: EventTarget,
document: JSManaged<Document>
}
impl Window {
pub fn new(document: JSManaged<Document>) -> JSManaged<Window> {
let win = ~Window {
eventtarget: EventTarget::new_inherited(WindowTargetTypeId),
document: document
};
JSManaged::new(win)
}
}
impl Reflectable for Window {
fn reflector<'a> (&'a self) -> &'a Reflector {
self.eventtarget.reflector()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment