Skip to content

Commit 3f33aa2

Browse files
committed
Replace dyn Iterator with monomorphized explicit trait
1 parent e633250 commit 3f33aa2

File tree

1 file changed

+41
-19
lines changed

1 file changed

+41
-19
lines changed

src/chunks.rs

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,8 @@ use anyhow::Context;
88
///
99
/// The last line in a chunk potentially reads over the chunk byte boundary to find the line end.
1010
/// In the same way the first line searches the line end.
11-
pub fn chunks(path: PathBuf) -> anyhow::Result<Chunks<BufReader<File>>> {
11+
pub fn chunks(path: PathBuf) -> anyhow::Result<Chunks<FileChunks>> {
1212
let size = File::open(&path)?.metadata()?.len();
13-
let it = (0..usize::MAX).map(move |_| {
14-
File::open(&path)
15-
.map(BufReader::new)
16-
.with_context(|| "Failed")
17-
});
18-
1913
let cpus = num_cpus::get() as u64;
2014
let chunk_size = MAX_CHUNK_SIZE.min(size / cpus / 10).max(MIN_CHUNK_SIZE);
2115
let chunks = if chunk_size == 0 {
@@ -24,7 +18,7 @@ pub fn chunks(path: PathBuf) -> anyhow::Result<Chunks<BufReader<File>>> {
2418
size / chunk_size + 1.min(size % chunk_size)
2519
} as usize;
2620
Ok(Chunks {
27-
chunk_data: Box::new(it),
21+
source: FileChunks { path },
2822
position: 0,
2923
count: 0,
3024
chunks,
@@ -33,20 +27,17 @@ pub fn chunks(path: PathBuf) -> anyhow::Result<Chunks<BufReader<File>>> {
3327
})
3428
}
3529

36-
pub struct Chunks<T> {
37-
chunk_data: Box<dyn Iterator<Item = anyhow::Result<T>> + Send>,
30+
pub struct Chunks<S: ChunkSource> {
31+
source: S,
3832
position: u64,
3933
count: usize,
4034
chunks: usize,
4135
chunk_size: u64,
4236
size: u64,
4337
}
4438

45-
impl<T> Iterator for Chunks<T>
46-
where
47-
T: BufRead + Seek,
48-
{
49-
type Item = Chunk<T>;
39+
impl<S: ChunkSource> Iterator for Chunks<S> {
40+
type Item = Chunk<S::Item>;
5041

5142
fn next(&mut self) -> Option<Self::Item> {
5243
if self.count == self.chunks {
@@ -55,7 +46,7 @@ where
5546

5647
let start = (self.count as u64) * self.chunk_size;
5748
self.count += 1;
58-
let f = self.chunk_data.next()?.ok()?;
49+
let f = self.source.call().ok()?;
5950
let (chunk, position) =
6051
Chunk::new(f, self.chunk_size, self.position, start, self.size).ok()?;
6152
self.position = position;
@@ -128,6 +119,26 @@ where
128119
}
129120
}
130121

122+
pub trait ChunkSource: Sized {
123+
type Item: Seek + BufRead;
124+
125+
fn call(&self) -> anyhow::Result<Self::Item>;
126+
}
127+
128+
pub struct FileChunks {
129+
path: PathBuf,
130+
}
131+
132+
impl ChunkSource for FileChunks {
133+
type Item = BufReader<File>;
134+
135+
fn call(&self) -> anyhow::Result<Self::Item> {
136+
File::open(&self.path)
137+
.map(BufReader::new)
138+
.with_context(|| "Failed")
139+
}
140+
}
141+
131142
const MIN_CHUNK_SIZE: u64 = 512 * 1024;
132143
const MAX_CHUNK_SIZE: u64 = 64 * 1024 * 1024;
133144

@@ -137,15 +148,14 @@ mod tests {
137148
use quickcheck::TestResult;
138149
use std::io::Cursor;
139150

140-
fn mem_chunks<'a>(mem: Vec<u8>, chunk_size: u64, size: u64) -> Chunks<impl BufRead + Seek> {
141-
let it = (0..usize::MAX).map(move |_| Ok(Cursor::new(mem.clone())));
151+
fn mem_chunks<'a>(bytes: Vec<u8>, chunk_size: u64, size: u64) -> Chunks<MemoryChunks> {
142152
let chunks = if chunk_size == 0 {
143153
0
144154
} else {
145155
size / chunk_size + 1.min(size % chunk_size)
146156
} as usize;
147157
Chunks {
148-
chunk_data: Box::new(it),
158+
source: MemoryChunks { bytes },
149159
position: 0,
150160
count: 0,
151161
chunks,
@@ -192,4 +202,16 @@ mod tests {
192202
.max_tests(300)
193203
.quickcheck(test_split_buf as fn(_, _) -> TestResult);
194204
}
205+
206+
struct MemoryChunks {
207+
bytes: Vec<u8>,
208+
}
209+
210+
impl ChunkSource for MemoryChunks {
211+
type Item = Cursor<Vec<u8>>;
212+
213+
fn call(&self) -> anyhow::Result<Self::Item> {
214+
Ok(Cursor::new(self.bytes.clone()))
215+
}
216+
}
195217
}

0 commit comments

Comments
 (0)