Refactor RCU to use the CamelCase naming convention

This commit is contained in:
Patrick Walton 2012-06-14 19:20:08 -07:00
parent 6c6f7f99e4
commit 0347e4408c
11 changed files with 155 additions and 160 deletions

View file

@ -6,14 +6,15 @@
export ControlMsg, PingMsg;
export content;
import result::extensions;
import dom::base::NodeScope;
import dom::rcu::writer_methods;
import dom::rcu::WriterMethods;
import dom::style;
import dom = dom::base;
import layout::layout_task;
import js::rust::methods;
import result::extensions;
enum ControlMsg {
ParseMsg(~str),
ExecuteMsg(~str),
@ -40,7 +41,7 @@ fn join_layout(scope: NodeScope, to_layout: chan<layout_task::Msg>) {
fn content(to_layout: chan<layout_task::Msg>) -> chan<ControlMsg> {
task::spawn_listener::<ControlMsg> {
|from_master|
let scope = dom::NodeScope();
let scope = NodeScope();
let rt = js::rust::rt();
loop {
alt from_master.recv() {

View file

@ -1,8 +1,11 @@
import dom::rcu::{writer_methods};
#[doc="The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements."]
import dom::rcu::WriterMethods;
import gfx::geometry::au;
import geom::size::Size2D;
import layout::base::layout_data;
import util::tree;
import dvec::{dvec, extensions};
enum NodeData = {
@ -61,12 +64,12 @@ enum ElementKind {
the primary box. Note that there may be multiple boxes per DOM node.
"]
type Node = rcu::handle<NodeData, layout_data>;
type Node = rcu::Handle<NodeData, layout_data>;
type NodeScope = rcu::scope<NodeData, layout_data>;
type NodeScope = rcu::Scope<NodeData, layout_data>;
fn NodeScope() -> NodeScope {
rcu::scope()
rcu::Scope()
}
impl NodeScope for NodeScope {
@ -85,7 +88,7 @@ impl of tree::rd_tree_ops<Node> for NodeScope {
}
fn with_tree_fields<R>(node: Node, f: fn(tree::fields<Node>) -> R) -> R {
self.rd(node) { |n| f(n.tree) }
self.read(node) { |n| f(n.tree) }
}
}
@ -95,7 +98,7 @@ impl of tree::wr_tree_ops<Node> for NodeScope {
}
fn with_tree_fields<R>(node: Node, f: fn(tree::fields<Node>) -> R) -> R {
self.wr(node) { |n| f(n.tree) }
self.write(node) { |n| f(n.tree) }
}
}

View file

@ -1,115 +1,108 @@
#[doc(str = "
Implements the RCU dom-sharing model. This model allows for a single
writer and any number of readers, but the writer must be able to
control and manage the lifetimes of the reader(s). For simplicity I
will describe the impl as though there were a single reader.
Implements the RCU DOM-sharing model. This model allows for a single writer and any number of
readers, but the writer must be able to control and manage the lifetimes of the reader(s). For
simplicity I will describe the implementation as though there were a single reader.
The basic idea is that every object in the RCU pool has both a reader
view and a writer view. The writer always sees the writer view, which
contains the most up-to-date values. The reader uses the reader view,
which contains the values as of the point where the reader was forked.
When the writer joins the reader, the reader view will be synchronized
with the writer view.
The basic idea is that every object in the RCU pool has both a reader view and a writer view. The
writer always sees the writer view, which contains the most up-to-date values. The reader uses the
reader view, which contains the values as of the point where the reader was forked. When the
writer joins the reader, the reader view will be synchronized with the writer view.
Internally, the way this works is using a copy-on-write scheme. Each
RCU node maintains two pointers (`rd_ptr` and `wr_ptr`). Assuming
that readers are active, when a writer wants to modify a node, it
first copies the reader's data into a new pointer. Any writes that
occur after that point (but before the reader is joined) will operate
on this same copy. When the reader is joined, any nodes which the
writer modified will free the stale reader data and update the reader
Internally, the way this works is using a copy-on-write scheme. Each RCU node maintains two
pointers (`read_ptr` and `write_ptr`). Assuming that readers are active, when a writer wants to
modify a node, it first copies the reader's data into a new pointer. Any writes that occur after
that point (but before the reader is joined) will operate on this same copy. When the reader is
joined, any nodes which the writer modified will free the stale reader data and update the reader
pointer to be the same as the writer pointer.
# Using the RCU APIs as a writer
You must first create a `scope` object. The scope object manages the
memory and the RCU operations. RCU'd objects of some sendable type
`T` are not referenced directly but rather through a `handle<T>`. To
create a new RCU object, you use `scope.handle(t)` where `t` is some
initial value of type `T`. To write to an RCU object, use
`scope.wr()` and to read from it use `scope.rd()`. Be sure not to use
the various `reader_methods`.
You must first create a `scope` object. The scope object manages the memory and the RCU
operations. RCU'd objects of some sendable type `T` are not referenced directly but rather through
a `handle<T>`. To create a new RCU object, you use `scope.handle(t)` where `t` is some initial
value of type `T`. To write to an RCU object, use `scope.write()` and to read from it use
`scope.read()`. Be sure not to use the various `ReaderMethods`.
Handles can be freely sent between tasks but the RCU scope cannot. It
must stay with the writer task. You are responsible for correctly
invoking `reader_forked()` and `reader_joined()` to keep the RCU scope
abreast of when the reader is active. Failure to do so will lead to
race conditions or worse.
Handles can be freely sent between tasks but the RCU scope cannot. It must stay with the writer
task. You are responsible for correctly invoking `reader_forked()` and `reader_joined()` to keep
the RCU scope abreast of when the reader is active. Failure to do so will lead to race conditions
or worse.
# Using the RCU APIs as a reader
Import the `reader_methods` impl. When you receive a handle, you can
invoke `h.rd { |v| ... }` and so forth. There is also a piece of
auxiliary data that can be optionally associated with each handle.
Import the `ReaderMethods` impl. When you receive a handle, you can invoke `h.read { |v| ... }`
and so forth. There is also a piece of auxiliary data that can be optionally associated with each
handle.
Note: if the type `T` contains mutable fields, then there is nothing
to stop the reader from mutating those fields in the `rd()` method.
Do not do this. It will lead to race conditions.
Note: if the type `T` contains mutable fields, then there is nothing to stop the reader from
mutating those fields in the `read()` method. Do not do this. It will lead to race conditions.
FIXME: We can enforce that this is not done by ensuring that the type `T` contains no mutable
fields.
# Auxiliary data
Readers can associate a piece of auxiliary data of type `A` along with
main nodes. This is convenient but dangerous: it is the reader's job
to ensure that this data remains live independent of the RCU nodes
themselves.
Readers can associate a piece of auxiliary data of type `A` along with main nodes. This is
convenient but dangerous: it is the reader's job to ensure that this data remains live independent
of the RCU nodes themselves.
")];
import ptr::extensions;
import core::libc::types::os::arch::c95::size_t;
export handle;
export reader_methods;
export writer_methods;
export scope;
export Handle;
export ReaderMethods;
export WriterMethods;
export Scope;
type scope_data<T:send,A> = {
type ScopeData<T:send,A> = {
mut layout_active: bool,
mut free_list: [handle<T,A>],
mut first_dirty: handle<T,A>
mut free_list: [Handle<T,A>],
mut first_dirty: Handle<T,A>
};
resource scope_rsrc<T:send,A>(d: scope_data<T,A>) {
resource ScopeResource<T:send,A>(d: ScopeData<T,A>) {
unsafe {
for d.free_list.each { |h| free_handle(h); }
}
}
type scope<T:send,A> = @scope_rsrc<T,A>;
type Scope<T:send,A> = @ScopeResource<T,A>;
type handle_data<T:send,A> = {mut rd_ptr: *T,
mut wr_ptr: *T,
mut rd_aux: *A,
mut next_dirty: handle<T,A>};
enum handle<T:send,A> {
_handle(*handle_data<T,A>)
type HandleData<T:send,A> = {mut read_ptr: *T,
mut write_ptr: *mut T,
mut read_aux: *A,
mut next_dirty: Handle<T,A>};
enum Handle<T:send,A> {
_Handle(*HandleData<T,A>)
}
impl private_methods<T:send,A> for handle<T,A> {
fn rd_ptr() -> *T unsafe { (**self).rd_ptr }
fn wr_ptr() -> *T unsafe { (**self).wr_ptr }
fn rd_aux() -> *A unsafe { (**self).rd_aux }
fn next_dirty() -> handle<T,A> unsafe { (**self).next_dirty }
impl HandlePrivate<T:send,A> for Handle<T,A> {
fn read_ptr() -> *T unsafe { (**self).read_ptr }
fn write_ptr() -> *mut T unsafe { (**self).write_ptr }
fn read_aux() -> *A unsafe { (**self).read_aux }
fn next_dirty() -> Handle<T,A> unsafe { (**self).next_dirty }
fn set_rd_ptr(t: *T) unsafe { (**self).rd_ptr = t; }
fn set_wr_ptr(t: *T) unsafe { (**self).wr_ptr = t; }
fn set_rd_aux(t: *A) unsafe { (**self).rd_aux = t; }
fn set_next_dirty(+h: handle<T,A>) unsafe { (**self).next_dirty = h; }
fn set_read_ptr(t: *T) unsafe { (**self).read_ptr = t; }
fn set_write_ptr(t: *mut T) unsafe { (**self).write_ptr = t; }
fn set_read_aux(t: *A) unsafe { (**self).read_aux = t; }
fn set_next_dirty(+h: Handle<T,A>) unsafe { (**self).next_dirty = h; }
pure fn is_null() -> bool { (*self).is_null() }
fn is_not_null() -> bool { (*self).is_not_null() }
}
impl reader_methods<T:send,A> for handle<T,A> {
#[doc(str = "access the reader's view of the handle's data")]
fn rd<U>(f: fn(T) -> U) -> U unsafe {
f(*self.rd_ptr())
impl ReaderMethods<T:send,A> for Handle<T,A> {
#[doc(str = "Access the reader's view of the handle's data.")]
fn read<U>(f: fn(T) -> U) -> U unsafe {
f(*self.read_ptr())
}
#[doc(str = "true if auxiliary data is associated with this handle")]
#[doc(str = "True if auxiliary data is associated with this handle.")]
fn has_aux() -> bool unsafe {
self.rd_aux().is_not_null()
self.read_aux().is_not_null()
}
#[doc(str = "set the auxiliary data associated with this handle.
@ -120,26 +113,24 @@ impl reader_methods<T:send,A> for handle<T,A> {
let p2 = p;
unsafe::forget(p2); // Bump the reference count.
(**self).rd_aux = ptr::addr_of(*p);
(**self).read_aux = ptr::addr_of(*p);
}
#[doc(str = "access the auxiliary data associated with this handle.")]
fn aux<U>(f: fn(A) -> U) -> U unsafe {
assert self.has_aux();
f(*self.rd_aux())
f(*self.read_aux())
}
}
impl private_methods<T: copy send,A> for scope<T,A> {
impl ScopePrivate<T: copy send,A> for Scope<T,A> {
fn clone(v: *T) -> *T unsafe {
let n: *mut T =
unsafe::reinterpret_cast(
libc::calloc(sys::size_of::<T>() as size_t, 1u as size_t));
unsafe::reinterpret_cast(libc::calloc(sys::size_of::<T>() as size_t, 1u as size_t));
// n.b.: this assignment will run the drop glue for <T,A>.
// *Hopefully* the fact that everything is initialized to NULL
// by calloc will make this ok. We may have to make the take
// glue be tolerant.
// n.b.: this assignment will run the drop glue for <T,A>. *Hopefully* the fact that
// everything is initialized to NULL by calloc will make this ok. We may have to make the
// take glue be tolerant of this.
*n = unsafe{*v};
ret unsafe::reinterpret_cast(n);
@ -151,22 +142,24 @@ unsafe fn free<T:send>(t: *T) {
libc::free(unsafe::reinterpret_cast(t));
}
unsafe fn free_handle<T:send,A>(h: handle<T,A>) {
free(h.rd_ptr());
if h.wr_ptr() != h.rd_ptr() { free(h.wr_ptr()); }
unsafe fn free_handle<T:send,A>(h: Handle<T,A>) {
free(h.read_ptr());
if h.write_ptr() != unsafe::reinterpret_cast(h.read_ptr()) {
free(unsafe::reinterpret_cast::<*mut T,*T>(h.write_ptr()));
}
}
fn null_handle<T:send,A>() -> handle<T,A> {
_handle(ptr::null())
fn null_handle<T:send,A>() -> Handle<T,A> {
_Handle(ptr::null())
}
fn scope<T:send,A>() -> scope<T,A> {
@scope_rsrc({mut layout_active: false,
mut free_list: [],
mut first_dirty: null_handle()})
fn Scope<T:send,A>() -> Scope<T,A> {
@ScopeResource({mut layout_active: false,
mut free_list: [],
mut first_dirty: null_handle()})
}
impl writer_methods<T:copy send,A> for scope<T,A> {
impl WriterMethods<T:copy send,A> for Scope<T,A> {
fn is_reader_forked() -> bool {
self.layout_active
}
@ -183,9 +176,9 @@ impl writer_methods<T:copy send,A> for scope<T,A> {
if self.first_dirty.is_not_null() {
let mut handle = self.first_dirty;
while (*handle).is_not_null() {
free(handle.rd_ptr());
free(handle.read_ptr());
handle.set_rd_ptr(handle.wr_ptr());
handle.set_read_ptr(unsafe::reinterpret_cast(handle.write_ptr()));
let next_handle = handle.next_dirty();
handle.set_next_dirty(null_handle());
handle = next_handle;
@ -197,31 +190,30 @@ impl writer_methods<T:copy send,A> for scope<T,A> {
self.layout_active = false;
}
fn rd<U>(h: handle<T,A>, f: fn(T) -> U) -> U unsafe {
// Use the wr_ptr, which may be more up to date than the
// rd_ptr or may not
f(*h.wr_ptr())
fn read<U>(h: Handle<T,A>, f: fn(T) -> U) -> U unsafe {
// Use the write_ptr, which may be more up to date than the read_ptr or may not
f(*h.write_ptr())
}
fn wr<U>(h: handle<T,A>, f: fn(T) -> U) -> U unsafe {
if self.layout_active && h.rd_ptr() == h.wr_ptr() {
fn write<U>(h: Handle<T,A>, f: fn(T) -> U) -> U unsafe {
if self.layout_active && h.read_ptr() == h.write_ptr() {
#debug["marking handle %? as dirty", h];
h.set_wr_ptr(self.clone(h.rd_ptr()));
h.set_write_ptr(unsafe::reinterpret_cast(self.clone(h.read_ptr())));
h.set_next_dirty(self.first_dirty);
self.first_dirty = h;
}
f(*h.wr_ptr())
f(*h.write_ptr())
}
fn handle(v: T) -> handle<T,A> unsafe {
let d: *handle_data<T,A> =
fn handle(v: T) -> Handle<T,A> unsafe {
let d: *HandleData<T,A> =
unsafe::reinterpret_cast(
libc::malloc(sys::size_of::<handle_data<T,A>>() as size_t));
(*d).rd_ptr = self.clone(ptr::addr_of(v));
(*d).wr_ptr = (*d).rd_ptr;
(*d).rd_aux = ptr::null();
libc::malloc(sys::size_of::<HandleData<T,A>>() as size_t));
(*d).read_ptr = self.clone(ptr::addr_of(v));
(*d).write_ptr = unsafe::reinterpret_cast((*d).read_ptr);
(*d).read_aux = ptr::null();
(*d).next_dirty = null_handle();
let h = _handle(d);
let h = _Handle(d);
self.free_list += [h];
ret h;
}
@ -240,11 +232,11 @@ mod test {
type processed = {flag: bool};
type animal_scope = scope<animal, processed>;
type animal_scope = Scope<animal, processed>;
#[test]
fn handles_get_freed() {
let s: animal_scope = scope();
let s: animal_scope = Scope();
s.handle({name:"henrietta", species:chicken(~{mut eggs_per_day:22u})});
s.handle({name:"ferdinand", species:bull(~{mut horns:3u})});
}
@ -265,7 +257,7 @@ mod test {
#[test]
fn interspersed_execution() {
let s: animal_scope = scope();
let s: animal_scope = Scope();
let henrietta =
s.handle({name:"henrietta",
species:chicken(~{mut eggs_per_day:0u})});
@ -283,30 +275,30 @@ mod test {
s.reader_forked();
let wait_chan = task::spawn_listener {|wait_port|
for uint::range(0u, iter2) { |_i|
comm::send(read_chan, henrietta.rd(read_characteristic));
comm::send(read_chan, ferdinand.rd(read_characteristic));
comm::send(read_chan, henrietta.read(read_characteristic));
comm::send(read_chan, ferdinand.read(read_characteristic));
comm::recv(wait_port);
}
};
let hrc = henrietta.rd(read_characteristic);
let hrc = henrietta.read(read_characteristic);
assert hrc == (i * iter2);
let frc = ferdinand.rd(read_characteristic);
let frc = ferdinand.read(read_characteristic);
assert frc == i * iter2;
for uint::range(0u, iter2) { |_i|
assert hrc == comm::recv(read_port);
s.wr(henrietta, mutate);
s.write(henrietta, mutate);
assert frc == comm::recv(read_port);
s.wr(ferdinand, mutate);
s.write(ferdinand, mutate);
comm::send(wait_chan, ());
}
s.reader_joined();
}
assert henrietta.rd(read_characteristic) == iter1 * iter2;
assert ferdinand.rd(read_characteristic) == iter1 * iter2;
assert henrietta.read(read_characteristic) == iter1 * iter2;
assert ferdinand.read(read_characteristic) == iter1 * iter2;
}
}

View file

@ -3,7 +3,7 @@
import dom::base::{Element, ElementKind, HTMLDivElement, HTMLImageElement, Node, NodeData};
import dom::base::{NodeKind};
import dom::rcu;
import dom::rcu::reader_methods;
import dom::rcu::ReaderMethods;
import gfx::geometry;
import gfx::geometry::{au, zero_size_au};
import geom::point::Point2D;
@ -62,7 +62,7 @@ impl of tree::rd_tree_ops<Node> for ntree {
}
fn with_tree_fields<R>(&&n: Node, f: fn(tree::fields<Node>) -> R) -> R {
n.rd { |n| f(n.tree) }
n.read { |n| f(n.tree) }
}
}
@ -138,7 +138,7 @@ impl PrivateNodeMethods for Node {
s += " ";
}
s += #fmt("%?", self.rd({ |n| copy n.kind }));
s += #fmt("%?", self.read({ |n| copy n.kind }));
#debug["%s", s];
for ntree.each_child(self) { |kid| kid.dump_indent(indent + 1u) }
@ -156,7 +156,7 @@ impl NodeMethods for Node {
mod test {
import dom::base::{Element, ElementData, HTMLDivElement, HTMLImageElement, Node, NodeKind};
import dom::base::{NodeScope, wr_tree_ops};
import dom::rcu::scope;
import dom::rcu::Scope;
import box_builder::{box_builder_methods};
/*
@ -186,7 +186,7 @@ mod test {
#[test]
#[ignore(reason = "busted")]
fn do_layout() {
let s = scope();
let s = Scope();
fn mk_img(size: Size2D<au>) -> ~ElementKind {
~HTMLImageElement({mut size: size})

View file

@ -2,7 +2,7 @@
import dom::base::{ElementData, HTMLDivElement, HTMLImageElement, Element, Text, Node};
import dom::style::{display_type, di_block, di_inline, di_none};
import dom::rcu::reader_methods;
import dom::rcu::ReaderMethods;
import gfx::geometry;
import layout::base::{BlockBox, Box, BoxKind, InlineBox, IntrinsicBox, NodeMethods, TextBox};
import layout::base::{appearance, btree, ntree, rd_tree_ops, wr_tree_ops};
@ -153,7 +153,7 @@ impl box_builder_priv for Node {
size.
"]
fn determine_box_kind() -> BoxKind {
alt self.rd({ |n| copy n.kind }) {
alt self.read({ |n| copy n.kind }) {
~Text(string) {
TextBox(@text_box(string))
}

View file

@ -1,7 +1,7 @@
#[doc="Inline layout."]
import dom::rcu;
import dom::rcu::reader_methods;
import dom::rcu::ReaderMethods;
import geom::point::Point2D;
import geom::size::Size2D;
import gfx::geometry::au;

View file

@ -1,14 +1,12 @@
#[doc = "
The layout task. Performs layout on the dom, builds display lists and sends
them to be rendered
The layout task. Performs layout on the DOM, builds display lists and sends them to be
rendered.
"];
import box_builder::box_builder_methods;
import dl = display_list;
import dom::base::Node;
import dom::rcu::scope;
import dom::rcu::Scope;
import dom::style::stylesheet;
import gfx::geometry::{au, au_to_px, box, px_to_au};
import gfx::renderer;

View file

@ -1,6 +1,7 @@
#[doc="Applies style to boxes."]
import dom::base::{HTMLImageElement, Element, Node};
import dom::rcu::reader_methods;
#[doc="Applies the appropriate CSS style to boxes."]
import dom::base::{Element, HTMLImageElement, Node};
import dom::rcu::ReaderMethods;
import image::base::load;
import layout::base::*;
import style::style_methods;
@ -17,7 +18,7 @@ impl ApplyStyleBoxMethods for @Box {
#[doc="Applies CSS style."]
fn apply_style() {
// Right now, we only handle images.
self.node.rd {
self.node.read {
|node|
alt node.kind {
~Element(element) {

View file

@ -1,12 +1,12 @@
#[doc="Perform css selector matching"]
#[doc="Performs CSS selector matching."]
import base::{layout_data};
import dom::base::{Element, ElementData, Node, Text};
import dom::style::{selector, style_decl, font_size, display, text_color, background_color,
stylesheet, element, child, descendant, sibling, attr, exact, exists, includes,
starts_with};
import dom::rcu::{reader_methods};
import dom::rcu::ReaderMethods;
import style::{computed_style, default_style_for_node_kind};
import base::{layout_data};
export matching_methods;
@ -72,7 +72,7 @@ impl priv_matching_methods for Node {
alt *sel {
child(_, _) | descendant(_, _) | sibling(_, _) { ret false; }
element(tag, attrs) {
alt self.rd { |n| copy *n.kind } {
alt self.read { |n| copy *n.kind } {
Element(elmt) {
if !(tag == "*" || tag == elmt.tag_name) {
ret false;
@ -100,7 +100,7 @@ impl priv_matching_methods for Node {
alt *sel {
element(str, atts) { ret self.matches_element(sel); }
child(sel1, sel2) {
alt self.rd { |n| n.tree.parent } {
alt self.read { |n| n.tree.parent } {
some(parent) {
ret self.matches_element(sel2) &&
parent.matches_selector(sel1);
@ -115,7 +115,7 @@ impl priv_matching_methods for Node {
//loop over all ancestors to check if they are the person
//we should be descended from.
let mut cur_parent = alt self.rd { |n| n.tree.parent } {
let mut cur_parent = alt self.read { |n| n.tree.parent } {
some(parent) { parent }
none { ret false; }
};
@ -123,7 +123,7 @@ impl priv_matching_methods for Node {
loop {
if cur_parent.matches_selector(sel1) { ret true; }
cur_parent = alt cur_parent.rd { |n| n.tree.parent } {
cur_parent = alt cur_parent.read { |n| n.tree.parent } {
some(parent) { parent }
none { ret false; }
};
@ -133,13 +133,13 @@ impl priv_matching_methods for Node {
if !self.matches_element(sel2) { ret false; }
// Loop over this node's previous siblings to see if they match.
alt self.rd { |n| n.tree.prev_sibling } {
alt self.read { |n| n.tree.prev_sibling } {
some(sib) {
let mut cur_sib = sib;
loop {
if cur_sib.matches_selector(sel1) { ret true; }
cur_sib = alt cur_sib.rd { |n| n.tree.prev_sibling } {
cur_sib = alt cur_sib.read { |n| n.tree.prev_sibling } {
some(sib) { sib }
none { break; }
};
@ -149,13 +149,13 @@ impl priv_matching_methods for Node {
}
// check the rest of the siblings
alt self.rd { |n| n.tree.next_sibling } {
alt self.read { |n| n.tree.next_sibling } {
some(sib) {
let mut cur_sib = sib;
loop {
if cur_sib.matches_selector(sel1) { ret true; }
cur_sib = alt cur_sib.rd { |n| n.tree.next_sibling } {
cur_sib = alt cur_sib.read { |n| n.tree.next_sibling } {
some(sib) { sib }
none { break; }
};
@ -174,7 +174,7 @@ impl matching_methods for Node {
#[doc="Compare an html element to a list of css rules and update its
style according to the rules matching it."]
fn match_css_style(styles : stylesheet) -> computed_style {
let node_kind = self.rd { |n| copy *n.kind };
let node_kind = self.read { |n| copy *n.kind };
let style =
@default_style_for_node_kind(node_kind);

View file

@ -3,7 +3,7 @@
import dom::style::{display_type, di_block, di_inline, di_none, stylesheet};
import dom::base::{Element, HTMLDivElement, HTMLHeadElement, HTMLImageElement, Node, NodeKind};
import dom::base::{Text};
import dom::rcu::reader_methods;
import dom::rcu::ReaderMethods;
import layout::base::*; // FIXME: resolve bug requires *
import matching::matching_methods;
import util::color::{Color, rgb};

View file

@ -1,20 +1,20 @@
#[doc="Constructs a DOM tree from an incoming token stream."]
import dom::rcu::writer_methods;
import dom::base::{Attr, Element, ElementData, ElementKind, HTMLDivElement, HTMLHeadElement};
import dom::base::{HTMLImageElement, Node, NodeScope, Text, UnknownElement, rd_tree_ops};
import dom::base::{wr_tree_ops};
import dom = dom::base;
import dvec::extensions;
import dom::rcu::WriterMethods;
import geom::size::Size2D;
import gfx::geometry;
import gfx::geometry::au;
import parser = parser::lexer::html;
import parser::token;
import dvec::extensions;
fn link_up_attribute(scope: NodeScope, node: Node, -key: str, -value: str) {
// TODO: Implement atoms so that we don't always perform string comparisons.
scope.rd(node) {
scope.read(node) {
|node_contents|
alt *node_contents.kind {
Element(element) {