From f0b66bc9df583bdc92562a92ca2ea7c7fd55138d Mon Sep 17 00:00:00 2001 From: Liang Wang Date: Mon, 8 Jun 2026 13:43:10 -0400 Subject: [PATCH 1/6] Document how to make the library `Send` --- scraper/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scraper/README.md b/scraper/README.md index f2d9af90..d989cafa 100644 --- a/scraper/README.md +++ b/scraper/README.md @@ -148,6 +148,14 @@ let document = tree.finish(); assert_eq!(document.html(), "hello"); ``` +### Using the library across threads +By default, many types of this library are `!Send` due to some internal data +structures used. To make them `Send`, enable the `atomic` feature flag. +```toml +[dependencies] +scraper = { version = "0.27.0", features = ["atomic"] } +``` + ## Contributing Please feel free to open pull requests. If you're planning on implementing From b5d7fd5aa61b3acfd0fb4521ae5425fdf10c3285 Mon Sep 17 00:00:00 2001 From: Liang Wang Date: Mon, 8 Jun 2026 16:47:11 -0400 Subject: [PATCH 2/6] fixup! Document how to make the library `Send` --- scraper/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scraper/README.md b/scraper/README.md index d989cafa..d71c989a 100644 --- a/scraper/README.md +++ b/scraper/README.md @@ -149,8 +149,12 @@ assert_eq!(document.html(), "hello"); ``` ### Using the library across threads -By default, many types of this library are `!Send` due to some internal data -structures used. To make them `Send`, enable the `atomic` feature flag. +The `html5ever` crate uses the +[`Tendril`](https://docs.rs/html5ever/latest/html5ever/tendril/struct.Tendril.html) +type as their reference counted string. By default, it's thread-local and thus +`!Send`, enabling the `atomic` flag will use the atomic counting version of +[`Tendril`](https://docs.rs/html5ever/latest/html5ever/tendril/struct.Tendril.html), +implementing `Send` and allow the use across threads. ```toml [dependencies] scraper = { version = "0.27.0", features = ["atomic"] } From dbe7455b3e24ad89deb018d5c80c3f0c65c195f2 Mon Sep 17 00:00:00 2001 From: Liang Wang Date: Tue, 9 Jun 2026 15:15:43 -0400 Subject: [PATCH 3/6] Drop `Tendril` as a direct dependency `html5ever` already exposes it a module --- Cargo.lock | 1 - scraper/Cargo.toml | 1 - scraper/src/html/mod.rs | 5 ++--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0cdfdd8b..d86fad77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -312,7 +312,6 @@ dependencies = [ "precomputed-hash", "selectors", "serde", - "tendril", ] [[package]] diff --git a/scraper/Cargo.toml b/scraper/Cargo.toml index 417966d4..2e2b0c9f 100644 --- a/scraper/Cargo.toml +++ b/scraper/Cargo.toml @@ -21,7 +21,6 @@ indexmap = { version = "2.14.0", optional = true } precomputed-hash = "0.1.1" selectors = "0.38.0" serde = { version = "1.0.228", optional = true } -tendril = "0.5.0" [dependencies.getopts] version = "0.2.24" diff --git a/scraper/src/html/mod.rs b/scraper/src/html/mod.rs index a201f1f8..00e87218 100644 --- a/scraper/src/html/mod.rs +++ b/scraper/src/html/mod.rs @@ -11,7 +11,7 @@ use html5ever::serialize::SerializeOpts; use html5ever::tree_builder::QuirksMode; use html5ever::{QualName, driver, serialize}; use selectors::matching::SelectorCaches; -use tendril::TendrilSink; +use html5ever::tendril::TendrilSink; use crate::selector::Selector; use crate::{ElementRef, Node}; @@ -65,12 +65,11 @@ impl Html { /// ``` /// # extern crate html5ever; /// # extern crate scraper; - /// # extern crate tendril; /// # fn main() { /// # let document = ""; /// use html5ever::driver::{self, ParseOpts}; /// use scraper::{Html, HtmlTreeSink}; - /// use tendril::TendrilSink; + /// use html5ever::tendril::TendrilSink; /// /// let parser = driver::parse_document(HtmlTreeSink::new(Html::new_document()), ParseOpts::default()); /// let html = parser.one(document); From 61e2475266dd0bbb898aa379c910729535f2c097 Mon Sep 17 00:00:00 2001 From: Liang Wang Date: Tue, 9 Jun 2026 15:45:03 -0400 Subject: [PATCH 4/6] fixup! Document how to make the library `Send` --- scraper/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scraper/README.md b/scraper/README.md index d71c989a..5f11ac4b 100644 --- a/scraper/README.md +++ b/scraper/README.md @@ -154,7 +154,7 @@ The `html5ever` crate uses the type as their reference counted string. By default, it's thread-local and thus `!Send`, enabling the `atomic` flag will use the atomic counting version of [`Tendril`](https://docs.rs/html5ever/latest/html5ever/tendril/struct.Tendril.html), -implementing `Send` and allow the use across threads. +implementing `Send` and allow their use across threads. ```toml [dependencies] scraper = { version = "0.27.0", features = ["atomic"] } From 6a419caa60da5d84bb9a32f898c5c95ee8259062 Mon Sep 17 00:00:00 2001 From: Liang Wang Date: Tue, 9 Jun 2026 16:13:01 -0400 Subject: [PATCH 5/6] Run cargo fmt --- scraper/src/html/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scraper/src/html/mod.rs b/scraper/src/html/mod.rs index 00e87218..504f3686 100644 --- a/scraper/src/html/mod.rs +++ b/scraper/src/html/mod.rs @@ -8,10 +8,10 @@ use std::iter::FusedIterator; use ego_tree::Tree; use ego_tree::iter::Nodes; use html5ever::serialize::SerializeOpts; +use html5ever::tendril::TendrilSink; use html5ever::tree_builder::QuirksMode; use html5ever::{QualName, driver, serialize}; use selectors::matching::SelectorCaches; -use html5ever::tendril::TendrilSink; use crate::selector::Selector; use crate::{ElementRef, Node}; From 0305377eaba83bd8cad99865fb7d934f0ec28ba9 Mon Sep 17 00:00:00 2001 From: Liang Wang Date: Tue, 9 Jun 2026 16:16:05 -0400 Subject: [PATCH 6/6] fixup! Run cargo fmt --- scraper/src/html/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scraper/src/html/mod.rs b/scraper/src/html/mod.rs index 504f3686..31873ee2 100644 --- a/scraper/src/html/mod.rs +++ b/scraper/src/html/mod.rs @@ -68,8 +68,8 @@ impl Html { /// # fn main() { /// # let document = ""; /// use html5ever::driver::{self, ParseOpts}; - /// use scraper::{Html, HtmlTreeSink}; /// use html5ever::tendril::TendrilSink; + /// use scraper::{Html, HtmlTreeSink}; /// /// let parser = driver::parse_document(HtmlTreeSink::new(Html::new_document()), ParseOpts::default()); /// let html = parser.one(document);