From 9ba6f62faa798d6978723334f41836519d3c7761 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 18 Aug 2015 18:11:58 +0200 Subject: [PATCH 1/2] Promise that add_attrs_if_missing() is called only on elements (fixes #121) --- examples/noop-tree-builder.rs | 4 +++- examples/print-tree-actions.rs | 1 + src/rcdom.rs | 8 ++++---- src/tree_builder/interface.rs | 5 +++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/noop-tree-builder.rs b/examples/noop-tree-builder.rs index 998c46b1..c4336bb1 100644 --- a/examples/noop-tree-builder.rs +++ b/examples/noop-tree-builder.rs @@ -74,7 +74,9 @@ impl TreeSink for Sink { fn append(&mut self, _parent: usize, _child: NodeOrText) { } fn append_doctype_to_document(&mut self, _: StrTendril, _: StrTendril, _: StrTendril) { } - fn add_attrs_if_missing(&mut self, _target: usize, _attrs: Vec) { } + fn add_attrs_if_missing(&mut self, target: usize, _attrs: Vec) { + assert!(self.names.contains_key(&target), "not an element"); + } fn remove_from_parent(&mut self, _target: usize) { } fn reparent_children(&mut self, _node: usize, _new_parent: usize) { } fn mark_script_already_started(&mut self, _node: usize) { } diff --git a/examples/print-tree-actions.rs b/examples/print-tree-actions.rs index 08324fdb..9eebcc14 100644 --- a/examples/print-tree-actions.rs +++ b/examples/print-tree-actions.rs @@ -104,6 +104,7 @@ impl TreeSink for Sink { } fn add_attrs_if_missing(&mut self, target: usize, attrs: Vec) { + assert!(self.names.contains_key(&target), "not an element"); println!("Add missing attributes to {}:", target); for attr in attrs.into_iter() { println!(" {:?} = {}", attr.name, attr.value); diff --git a/src/rcdom.rs b/src/rcdom.rs index 062b8ef0..0d0dcf8a 100644 --- a/src/rcdom.rs +++ b/src/rcdom.rs @@ -244,10 +244,10 @@ impl TreeSink for RcDom { fn add_attrs_if_missing(&mut self, target: Handle, mut attrs: Vec) { let mut node = target.borrow_mut(); - // FIXME: mozilla/rust#15609 - let existing = match node.deref_mut().node { - Element(_, ref mut attrs) => attrs, - _ => return, + let existing = if let Element(_, ref mut attrs) = node.deref_mut().node { + attrs + } else { + panic!("not an element") }; // FIXME: quadratic time diff --git a/src/tree_builder/interface.rs b/src/tree_builder/interface.rs index 5aee28f8..2f579544 100644 --- a/src/tree_builder/interface.rs +++ b/src/tree_builder/interface.rs @@ -103,8 +103,9 @@ pub trait TreeSink { public_id: StrTendril, system_id: StrTendril); - /// Add each attribute to the given element, if no attribute - /// with that name already exists. + /// Add each attribute to the given element, if no attribute with that name + /// already exists. The tree builder promises this will never be called + /// with something else than an element. fn add_attrs_if_missing(&mut self, target: Self::Handle, attrs: Vec); /// Detach the given node from its parent. From dfd64ecdff4f597c213a1c4f0a60fd8c8e9dbad3 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 18 Aug 2015 18:19:53 +0200 Subject: [PATCH 2/2] Fix the algorithmic complexity of RcDom::add_attrs_if_missing() --- src/rcdom.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/rcdom.rs b/src/rcdom.rs index 0d0dcf8a..667c75ae 100644 --- a/src/rcdom.rs +++ b/src/rcdom.rs @@ -13,6 +13,7 @@ //! web browser using it. :) use std::cell::RefCell; +use std::collections::HashSet; use std::default::Default; use std::borrow::Cow; use std::io::{self, Write}; @@ -242,7 +243,7 @@ impl TreeSink for RcDom { append(&self.document, new_node(Doctype(name, public_id, system_id))); } - fn add_attrs_if_missing(&mut self, target: Handle, mut attrs: Vec) { + fn add_attrs_if_missing(&mut self, target: Handle, attrs: Vec) { let mut node = target.borrow_mut(); let existing = if let Element(_, ref mut attrs) = node.deref_mut().node { attrs @@ -250,10 +251,11 @@ impl TreeSink for RcDom { panic!("not an element") }; - // FIXME: quadratic time - attrs.retain(|attr| - !existing.iter().any(|e| e.name == attr.name)); - existing.extend(attrs.into_iter()); + let existing_names = + existing.iter().map(|e| e.name.clone()).collect::>(); + existing.extend(attrs.into_iter().filter(|attr| { + !existing_names.contains(&attr.name) + })); } fn remove_from_parent(&mut self, target: Handle) {