Skip to content

Commit

Permalink
Merge pull request #101 from adamreichold/lazily-fetch-id-classes
Browse files Browse the repository at this point in the history
RFC: Lazily fetch id and classes
  • Loading branch information
cfvescovo committed Mar 3, 2023
2 parents db9679d + bdd1c1e commit 8a3723f
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 33 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ smallvec = "1.10.0"
tendril = "0.4.3"
ahash = "0.8"
indexmap = { version = "1.9.2", optional = true }
once_cell = "1.0"

[dependencies.getopts]
version = "0.2.21"
Expand Down
4 changes: 2 additions & 2 deletions src/element_ref/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ impl<'a> Element for ElementRef<'a> {
}

fn has_id(&self, id: &CssLocalName, case_sensitivity: CaseSensitivity) -> bool {
match self.value().id {
Some(ref val) => case_sensitivity.eq(id.0.as_bytes(), val.as_bytes()),
match self.value().id() {
Some(val) => case_sensitivity.eq(id.0.as_bytes(), val.as_bytes()),
None => false,
}
}
Expand Down
68 changes: 37 additions & 31 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@

#[cfg(not(feature = "deterministic"))]
use ahash::AHashMap as HashMap;
use ahash::AHashSet as HashSet;
#[cfg(not(feature = "deterministic"))]
use std::collections::hash_map;
use std::collections::hash_set;
use std::fmt;
use std::ops::Deref;
use std::slice::Iter as SliceIter;

use crate::StrTendril;
use crate::{CaseSensitivity, StrTendril};
use html5ever::{Attribute, LocalName, QualName};
use selectors::attr::CaseSensitivity;
use once_cell::unsync::OnceCell;

/// An HTML node.
// `Element` is usally the most common variant and hence boxing it
Expand Down Expand Up @@ -228,41 +227,27 @@ pub struct Element {
/// The element name.
pub name: QualName,

/// The element ID.
pub id: Option<LocalName>,

/// The element classes.
pub classes: HashSet<LocalName>,

/// The element attributes.
pub attrs: Attributes,

id: OnceCell<Option<StrTendril>>,

classes: OnceCell<Vec<LocalName>>,
}

impl Element {
#[doc(hidden)]
pub fn new(name: QualName, attributes: Vec<Attribute>) -> Self {
let mut classes: HashSet<LocalName> = HashSet::new();
let mut attrs = Attributes::with_capacity(attributes.len());
let mut id: Option<LocalName> = None;

for a in attributes {
match a.name.local.deref() {
"id" => {
id = Some(LocalName::from(a.value.deref()));
}
"class" => {
classes.extend(a.value.deref().split_whitespace().map(LocalName::from));
}
_ => (),
};
attrs.insert(a.name, crate::tendril_util::make(a.value));
}
let attrs = attributes
.into_iter()
.map(|a| (a.name, crate::tendril_util::make(a.value)))
.collect();

Element {
attrs,
name,
id,
classes,
id: OnceCell::new(),
classes: OnceCell::new(),
}
}

Expand All @@ -273,7 +258,14 @@ impl Element {

/// Returns the element ID.
pub fn id(&self) -> Option<&str> {
self.id.as_deref()
self.id
.get_or_init(|| {
self.attrs
.iter()
.find(|(name, _)| name.local.as_ref() == "id")
.map(|(_, value)| value.clone())
})
.as_deref()
}

/// Returns true if element has the class.
Expand All @@ -284,8 +276,22 @@ impl Element {

/// Returns an iterator over the element's classes.
pub fn classes(&self) -> Classes {
let classes = self.classes.get_or_init(|| {
let mut classes: Vec<LocalName> = self
.attrs
.iter()
.filter(|(name, _)| name.local.as_ref() == "class")
.flat_map(|(_, value)| value.split_whitespace().map(LocalName::from))
.collect();

classes.sort_unstable();
classes.dedup();

classes
});

Classes {
inner: self.classes.iter(),
inner: classes.iter(),
}
}

Expand All @@ -307,7 +313,7 @@ impl Element {
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct Classes<'a> {
inner: hash_set::Iter<'a, LocalName>,
inner: SliceIter<'a, LocalName>,
}

impl<'a> Iterator for Classes<'a> {
Expand Down

0 comments on commit 8a3723f

Please sign in to comment.