Skip to content

Commit

Permalink
Work around refcell limitations in example code by leaking memory.
Browse files Browse the repository at this point in the history
  • Loading branch information
jdm committed Aug 7, 2024
1 parent 1ef8f76 commit 6a60698
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 23 deletions.
40 changes: 23 additions & 17 deletions html5ever/examples/noop-tree-builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
extern crate html5ever;

use std::borrow::Cow;
use std::cell::Cell;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::io;

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

struct Sink<'a> {
struct Sink {
next_id: Cell<usize>,
names: &'a mut HashMap<usize, QualName>,
names: RefCell<HashMap<usize, &'static QualName>>,
}

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

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

fn elem_name(&self, _target: &usize) -> ExpandedName {
//XXX(jdm)
//let names = self.names.borrow();
//Ref::map(names, |names| names.get(target).expect("not an element").expanded())
//self.names.get(target).expect("not an element").expanded()
todo!()
fn elem_name(&self, target: &usize) -> ExpandedName {
self.names
.borrow()
.get(target)
.expect("not an element")
.expanded()
}

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

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

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

// Read HTML from the standard input and parse it
Expand Down
14 changes: 8 additions & 6 deletions html5ever/examples/print-tree-actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use html5ever::{Attribute, ExpandedName, QualName};

struct Sink {
next_id: Cell<usize>,
names: RefCell<HashMap<usize, QualName>>,
names: RefCell<HashMap<usize, &'static QualName>>,
}

impl Sink {
Expand Down Expand Up @@ -67,16 +67,18 @@ impl TreeSink for Sink {
x == y
}

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

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

Expand Down

0 comments on commit 6a60698

Please sign in to comment.