Skip to content

Commit 3498a40

Browse files
committed
Work around refcell limitations in example code by leaking memory.
1 parent 1ef8f76 commit 3498a40

File tree

2 files changed

+30
-22
lines changed

2 files changed

+30
-22
lines changed

html5ever/examples/noop-tree-builder.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
extern crate html5ever;
1212

1313
use std::borrow::Cow;
14-
use std::cell::Cell;
14+
use std::cell::{Cell, RefCell};
1515
use std::collections::HashMap;
1616
use std::io;
1717

@@ -20,12 +20,12 @@ use html5ever::tendril::*;
2020
use html5ever::tree_builder::{ElementFlags, NodeOrText, QuirksMode, TreeSink};
2121
use html5ever::{Attribute, ExpandedName, QualName};
2222

23-
struct Sink<'a> {
23+
struct Sink {
2424
next_id: Cell<usize>,
25-
names: &'a mut HashMap<usize, QualName>,
25+
names: RefCell<HashMap<usize, &'static QualName>>,
2626
}
2727

28-
impl <'a> Sink<'a> {
28+
impl Sink {
2929
fn get_id(&self) -> usize {
3030
let id = self.next_id.get();
3131
self.next_id.set(id + 2);
@@ -37,7 +37,7 @@ impl <'a> Sink<'a> {
3737
/// is processed. In this case the DOM elements are written into the "names" hashmap.
3838
///
3939
/// For deeper understating of each function go to the TreeSink declaration.
40-
impl <'a> TreeSink for Sink<'a> {
40+
impl TreeSink for Sink {
4141
type Handle = usize;
4242
type Output = Self;
4343
fn finish(self) -> Self {
@@ -49,7 +49,8 @@ impl <'a> TreeSink for Sink<'a> {
4949
}
5050

5151
fn get_template_contents(&self, target: &usize) -> usize {
52-
if let Some(expanded_name!(html "template")) = self.names.get(target).map(|n| n.expanded())
52+
if let Some(expanded_name!(html "template")) =
53+
self.names.borrow().get(target).map(|n| n.expanded())
5354
{
5455
target + 1
5556
} else {
@@ -61,17 +62,23 @@ impl <'a> TreeSink for Sink<'a> {
6162
x == y
6263
}
6364

64-
fn elem_name(&self, _target: &usize) -> ExpandedName {
65-
//XXX(jdm)
66-
//let names = self.names.borrow();
67-
//Ref::map(names, |names| names.get(target).expect("not an element").expanded())
68-
//self.names.get(target).expect("not an element").expanded()
69-
todo!()
65+
fn elem_name(&self, target: &usize) -> ExpandedName {
66+
self.names
67+
.borrow()
68+
.get(target)
69+
.expect("not an element")
70+
.expanded()
7071
}
7172

72-
fn create_element(&self, _name: QualName, _: Vec<Attribute>, _: ElementFlags) -> usize {
73+
fn create_element(&self, name: QualName, _: Vec<Attribute>, _: ElementFlags) -> usize {
7374
let id = self.get_id();
74-
//self.names.insert(id, name);
75+
// N.B. We intentionally leak memory here to minimize the implementation complexity
76+
// of this example code. A real implementation would either want to use a real
77+
// real DOM tree implentation, or else use an arena as the backing store for
78+
// memory used by the parser.
79+
self.names
80+
.borrow_mut()
81+
.insert(id, Box::leak(Box::new(name)));
7582
id
7683
}
7784

@@ -100,7 +107,7 @@ impl <'a> TreeSink for Sink<'a> {
100107

101108
fn append_doctype_to_document(&self, _: StrTendril, _: StrTendril, _: StrTendril) {}
102109
fn add_attrs_if_missing(&self, target: &usize, _attrs: Vec<Attribute>) {
103-
assert!(self.names.contains_key(target), "not an element");
110+
assert!(self.names.borrow().contains_key(target), "not an element");
104111
}
105112
fn remove_from_parent(&self, _target: &usize) {}
106113
fn reparent_children(&self, _node: &usize, _new_parent: &usize) {}
@@ -110,10 +117,9 @@ impl <'a> TreeSink for Sink<'a> {
110117
/// In this example we implement the TreeSink trait which takes each parsed elements and insert
111118
/// it to a hashmap, while each element is given a numeric id.
112119
fn main() {
113-
let mut names = HashMap::new();
114120
let sink = Sink {
115121
next_id: Cell::new(1),
116-
names: &mut names,
122+
names: RefCell::new(HashMap::new()),
117123
};
118124

119125
// Read HTML from the standard input and parse it

html5ever/examples/print-tree-actions.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use html5ever::{Attribute, ExpandedName, QualName};
2424

2525
struct Sink {
2626
next_id: Cell<usize>,
27-
names: RefCell<HashMap<usize, QualName>>,
27+
names: RefCell<HashMap<usize, &'static QualName>>,
2828
}
2929

3030
impl Sink {
@@ -68,15 +68,17 @@ impl TreeSink for Sink {
6868
}
6969

7070
fn elem_name(&self, _target: &usize) -> ExpandedName {
71-
//XXX(jdm)
72-
//self.names.borrow().get(target).cloned().expect("not an element").expanded()
73-
todo!()
71+
self.names.borrow().get(target).cloned().expect("not an element").expanded()
7472
}
7573

7674
fn create_element(&self, name: QualName, _: Vec<Attribute>, _: ElementFlags) -> usize {
7775
let id = self.get_id();
7876
println!("Created {:?} as {}", name, id);
79-
//self.names.borrow_mut().insert(id, name);
77+
// N.B. We intentionally leak memory here to minimize the implementation complexity
78+
// of this example code. A real implementation would either want to use a real
79+
// real DOM tree implentation, or else use an arena as the backing store for
80+
// memory used by the parser.
81+
self.names.borrow_mut().insert(id, Box::leak(Box::new(name)));
8082
id
8183
}
8284

0 commit comments

Comments
 (0)