Skip to content

Commit a77bd2a

Browse files
committed
Implement a parallel iterator for WordList
impl ExactSizeIterator for WordListIter impl DoubleEndedIterator for WordListIter Thank you ChatGPT, rayon's documentation wasn't really helpful for this process honestly
1 parent 7f0f8de commit a77bd2a

File tree

4 files changed

+143
-0
lines changed

4 files changed

+143
-0
lines changed

Cargo.lock

+46
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fontheight-core/Cargo.toml

+7
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,18 @@ license = "Apache-2.0"
99
readme = "../README.md"
1010
repository = "https://github.com/googlefonts/fontheight"
1111

12+
[features]
13+
default = [
14+
"rayon",
15+
]
16+
rayon = ["dep:rayon"]
17+
1218
[dependencies]
1319
itertools = "0.14.0"
1420
kurbo = "0.11.1"
1521
log = { workspace = true }
1622
ordered-float = "4.6"
23+
rayon = { version = "1.10", optional = true }
1724
rustybuzz = "0.20.1"
1825
skrifa = "0.26.5"
1926
thiserror = "2"

fontheight-core/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ mod pens;
2121
mod word_lists;
2222

2323
pub use locations::Location;
24+
#[cfg(feature = "rayon")]
25+
pub use word_lists::rayon::ParWordListIter;
2426
pub use word_lists::*;
2527

2628
pub struct Reporter<'a> {

fontheight-core/src/word_lists.rs

+88
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,96 @@ impl<'a> Iterator for WordListIter<'a> {
9191
}
9292
}
9393

94+
impl ExactSizeIterator for WordListIter<'_> {
95+
fn len(&self) -> usize {
96+
self.0.len()
97+
}
98+
}
99+
100+
impl DoubleEndedIterator for WordListIter<'_> {
101+
fn next_back(&mut self) -> Option<Self::Item> {
102+
self.0.next_back().map(String::as_ref)
103+
}
104+
}
105+
94106
#[derive(Debug, Error)]
95107
pub enum WordListError {
96108
#[error("failed to read from {}: {}", .0.display(), .1)]
97109
FailedToRead(PathBuf, io::Error),
98110
}
111+
112+
#[cfg(feature = "rayon")]
113+
pub(crate) mod rayon {
114+
use rayon::iter::{
115+
plumbing::{
116+
bridge, Consumer, Producer, ProducerCallback, UnindexedConsumer,
117+
},
118+
IndexedParallelIterator, ParallelIterator,
119+
};
120+
121+
use super::{WordList, WordListIter};
122+
123+
#[derive(Debug)]
124+
pub struct ParWordListIter<'a>(&'a [String]);
125+
126+
impl<'a> ParallelIterator for ParWordListIter<'a> {
127+
type Item = &'a str;
128+
129+
fn drive_unindexed<C>(self, consumer: C) -> C::Result
130+
where
131+
C: UnindexedConsumer<Self::Item>,
132+
{
133+
bridge(self, consumer)
134+
}
135+
136+
fn opt_len(&self) -> Option<usize> {
137+
Some(self.0.len())
138+
}
139+
}
140+
141+
impl<'a> Producer for ParWordListIter<'a> {
142+
type IntoIter = WordListIter<'a>;
143+
type Item = &'a str;
144+
145+
fn into_iter(self) -> Self::IntoIter {
146+
WordListIter(self.0.iter())
147+
}
148+
149+
fn split_at(self, index: usize) -> (Self, Self) {
150+
let (left, right) = self.0.split_at(index);
151+
(ParWordListIter(left), ParWordListIter(right))
152+
}
153+
}
154+
155+
impl IndexedParallelIterator for ParWordListIter<'_> {
156+
fn len(&self) -> usize {
157+
self.0.len()
158+
}
159+
160+
fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
161+
bridge(self, consumer)
162+
}
163+
164+
fn with_producer<CB>(self, callback: CB) -> CB::Output
165+
where
166+
CB: ProducerCallback<Self::Item>,
167+
{
168+
callback.callback(self)
169+
}
170+
}
171+
172+
impl<'a> rayon::iter::IntoParallelIterator for &'a WordList {
173+
type Item = &'a str;
174+
type Iter = ParWordListIter<'a>;
175+
176+
fn into_par_iter(self) -> Self::Iter {
177+
ParWordListIter(&self.words)
178+
}
179+
}
180+
181+
impl WordList {
182+
pub fn par_iter(&self) -> ParWordListIter {
183+
ParWordListIter(&self.words)
184+
}
185+
}
186+
}

0 commit comments

Comments
 (0)