1use std::io::{self, Write};
2
3pub trait Writer {
8 fn write(&mut self, bytes: &[u8]);
9
10 #[inline]
11 fn write_byte(&mut self, byte: u8) {
12 self.write(&[byte]);
13 }
14
15 #[inline]
16 fn reserve(&mut self, _additional: usize) {}
17
18 fn write_with(&mut self, len: usize, fill: impl FnOnce(&mut [u8]) -> usize) {
21 let mut buffer = vec![0; len];
22 let written = fill(&mut buffer).min(len);
23 self.write(buffer.get(..written).unwrap_or_default());
24 }
25
26 fn append_with<T>(&mut self, len: usize, append: impl FnOnce(&mut Vec<u8>) -> T) -> T {
32 let mut buffer = Vec::with_capacity(len);
33 let result = append(&mut buffer);
34 self.write(&buffer);
35 result
36 }
37
38 #[inline]
41 fn append_limit(&self) -> usize {
42 IO_BUFFER_MAX
43 }
44}
45
46impl Writer for Vec<u8> {
47 #[inline(always)]
48 fn write(&mut self, bytes: &[u8]) {
49 self.extend_from_slice(bytes);
50 }
51
52 #[inline(always)]
53 fn write_byte(&mut self, byte: u8) {
54 self.push(byte);
55 }
56
57 #[inline]
58 fn reserve(&mut self, additional: usize) {
59 Vec::reserve(self, additional);
60 }
61
62 #[inline]
63 fn write_with(&mut self, len: usize, fill: impl FnOnce(&mut [u8]) -> usize) {
64 let start = self.len();
65 self.resize(start + len, 0);
66 let written = fill(self.get_mut(start..).unwrap_or_default()).min(len);
67 self.truncate(start + written);
68 }
69
70 #[inline(always)]
71 fn append_with<T>(&mut self, _len: usize, append: impl FnOnce(&mut Vec<u8>) -> T) -> T {
72 append(self)
73 }
74
75 #[inline(always)]
76 fn append_limit(&self) -> usize {
77 usize::MAX
78 }
79}
80
81impl<W: Writer + ?Sized> Writer for &mut W {
82 #[inline(always)]
83 fn write(&mut self, bytes: &[u8]) {
84 (**self).write(bytes);
85 }
86
87 #[inline(always)]
88 fn write_byte(&mut self, byte: u8) {
89 (**self).write_byte(byte);
90 }
91
92 #[inline]
93 fn reserve(&mut self, additional: usize) {
94 (**self).reserve(additional);
95 }
96
97 #[inline]
98 fn write_with(&mut self, len: usize, fill: impl FnOnce(&mut [u8]) -> usize) {
99 (**self).write_with(len, fill);
100 }
101
102 #[inline(always)]
103 fn append_with<T>(&mut self, len: usize, append: impl FnOnce(&mut Vec<u8>) -> T) -> T {
104 (**self).append_with(len, append)
105 }
106
107 #[inline(always)]
108 fn append_limit(&self) -> usize {
109 (**self).append_limit()
110 }
111}
112
113pub(crate) const IO_BUFFER_MAX: usize = 64 * 1024;
114pub(crate) const IO_BUFFER_MIN: usize = 4 * 1024;
115
116pub struct IoWriter<W: Write> {
123 inner: W,
124 buffer: Vec<u8>,
125 error: Option<io::Error>,
126}
127
128impl<W: Write> IoWriter<W> {
129 pub fn new(inner: W) -> Self {
130 Self::with_capacity(IO_BUFFER_MAX, inner)
131 }
132
133 pub fn with_capacity(capacity: usize, inner: W) -> Self {
134 IoWriter {
135 inner,
136 buffer: Vec::with_capacity(capacity.max(1)),
137 error: None,
138 }
139 }
140
141 fn write_inner(&mut self, bytes: &[u8]) {
142 if self.error.is_none()
143 && let Err(err) = self.inner.write_all(bytes)
144 {
145 self.error = Some(err);
146 }
147 }
148
149 fn flush_buffer(&mut self) {
150 if !self.buffer.is_empty() {
151 let buffer = std::mem::take(&mut self.buffer);
152 self.write_inner(&buffer);
153 self.buffer = buffer;
154 self.buffer.clear();
155 }
156 }
157
158 pub fn finish(mut self) -> io::Result<W> {
161 self.flush_buffer();
162 match self.error.take() {
163 Some(err) => Err(err),
164 None => Ok(self.inner),
165 }
166 }
167
168 pub fn into_result(self) -> io::Result<()> {
169 self.finish().map(|_| ())
170 }
171}
172
173impl<W: Write> Writer for IoWriter<W> {
174 #[inline]
175 fn write(&mut self, bytes: &[u8]) {
176 if bytes.len() > self.buffer.capacity() - self.buffer.len() {
177 self.flush_buffer();
178 if bytes.len() >= self.buffer.capacity() {
179 self.write_inner(bytes);
180 return;
181 }
182 }
183 self.buffer.extend_from_slice(bytes);
184 }
185
186 #[inline]
187 fn write_byte(&mut self, byte: u8) {
188 if self.buffer.len() == self.buffer.capacity() {
189 self.flush_buffer();
190 }
191 self.buffer.push(byte);
192 }
193
194 #[inline]
195 fn write_with(&mut self, len: usize, fill: impl FnOnce(&mut [u8]) -> usize) {
196 if len > self.buffer.capacity() - self.buffer.len() {
197 self.flush_buffer();
198 }
199 let start = self.buffer.len();
200 self.buffer.resize(start + len, 0);
201 let written = fill(self.buffer.get_mut(start..).unwrap_or_default()).min(len);
202 self.buffer.truncate(start + written);
203 }
204
205 #[inline]
206 fn append_with<T>(&mut self, len: usize, append: impl FnOnce(&mut Vec<u8>) -> T) -> T {
207 let capacity = self.buffer.capacity();
208 if len > capacity - self.buffer.len() {
209 self.flush_buffer();
210 }
211 let result = append(&mut self.buffer);
212 if self.buffer.capacity() > capacity {
213 self.flush_buffer();
214 self.buffer.shrink_to(capacity);
215 }
216 result
217 }
218
219 #[inline]
220 fn append_limit(&self) -> usize {
221 self.buffer.capacity()
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 struct FailAfter(usize);
230
231 impl Write for FailAfter {
232 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
233 if self.0 == 0 {
234 Err(io::Error::other("full"))
235 } else {
236 self.0 = self.0.saturating_sub(buf.len());
237 Ok(buf.len())
238 }
239 }
240
241 fn flush(&mut self) -> io::Result<()> {
242 Ok(())
243 }
244 }
245
246 #[derive(Default)]
247 struct Chunks {
248 writes: Vec<Vec<u8>>,
249 }
250
251 impl Write for Chunks {
252 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
253 self.writes.push(buf.to_vec());
254 Ok(buf.len())
255 }
256
257 fn flush(&mut self) -> io::Result<()> {
258 Ok(())
259 }
260 }
261
262 impl Chunks {
263 fn joined(&self) -> Vec<u8> {
264 self.writes.iter().flatten().copied().collect()
265 }
266 }
267
268 #[test]
269 fn io_writer_buffers_and_flushes_in_order() {
270 let mut writer = IoWriter::with_capacity(8, Vec::new());
271 writer.write(b"abc");
272 writer.write_byte(b'd');
273 writer.write(b"efghij");
274 writer.write_with(4, |region| {
275 region.copy_from_slice(b"KLMN");
276 2
277 });
278 writer.write(b"0123456789abcdef");
279 assert_eq!(writer.finish().unwrap(), b"abcdefghijKL0123456789abcdef");
280 }
281
282 #[test]
283 fn io_writer_reports_the_first_error() {
284 let mut writer = IoWriter::with_capacity(4, FailAfter(6));
285 writer.write(b"abcdef");
286 writer.write(b"ghij");
287 writer.write(b"klmn");
288 assert!(writer.into_result().is_err());
289 }
290
291 #[test]
292 fn io_writer_keeps_writing_after_the_first_error() {
293 let mut writer = IoWriter::with_capacity(4, FailAfter(0));
294 for _ in 0..100 {
295 writer.write(b"abcdefgh");
296 writer.write_byte(b'x');
297 }
298 let error = writer.into_result().expect_err("error expected");
299 assert_eq!(error.to_string(), "full");
300 }
301
302 #[test]
303 fn io_writer_passes_large_writes_through() {
304 let mut writer = IoWriter::with_capacity(8, Chunks::default());
305 writer.write(b"ab");
306 writer.write(b"0123456789");
307 writer.write(b"cd");
308 let chunks = writer.finish().unwrap();
309 assert_eq!(chunks.writes.len(), 3);
310 assert_eq!(chunks.writes.first().map(Vec::as_slice), Some(b"ab".as_ref()));
311 assert_eq!(chunks.writes.get(1).map(Vec::as_slice), Some(b"0123456789".as_ref()));
312 assert_eq!(chunks.joined(), b"ab0123456789cd");
313 }
314
315 #[test]
316 fn io_writer_byte_writes_never_exceed_the_buffer() {
317 let mut writer = IoWriter::with_capacity(4, Chunks::default());
318 for byte in b"abcdefghij" {
319 writer.write_byte(*byte);
320 }
321 let chunks = writer.finish().unwrap();
322 assert!(chunks.writes.iter().all(|chunk| chunk.len() <= 4), "{:?}", chunks.writes);
323 assert_eq!(chunks.joined(), b"abcdefghij");
324 }
325
326 #[test]
327 fn io_writer_write_with_grows_beyond_the_buffer() {
328 let mut writer = IoWriter::with_capacity(4, Chunks::default());
329 writer.write(b"ab");
330 writer.write_with(16, |region| {
331 for (slot, byte) in region.iter_mut().zip(b"0123456789".iter()) {
332 *slot = *byte;
333 }
334 10
335 });
336 writer.write(b"cd");
337 let chunks = writer.finish().unwrap();
338 assert_eq!(chunks.joined(), b"ab0123456789cd");
339 }
340
341 #[test]
342 fn io_writer_write_with_keeps_only_the_filled_prefix() {
343 let mut writer = IoWriter::with_capacity(64, Vec::new());
344 writer.write_with(8, |region| {
345 assert_eq!(region.len(), 8);
346 assert!(region.iter().all(|byte| *byte == 0));
347 region.iter_mut().for_each(|slot| *slot = b'z');
348 3
349 });
350 writer.write_with(8, |_| 0);
351 writer.write(b"!");
352 assert_eq!(writer.finish().unwrap(), b"zzz!");
353 }
354
355 #[test]
356 fn io_writer_write_with_caps_the_reported_length() {
357 let mut writer = IoWriter::with_capacity(64, Vec::new());
358 writer.write_with(4, |region| {
359 region.copy_from_slice(b"abcd");
360 usize::MAX
361 });
362 assert_eq!(writer.finish().unwrap(), b"abcd");
363 }
364
365 #[test]
366 fn vec_write_with_keeps_only_the_filled_prefix() {
367 let mut out = b"x".to_vec();
368 out.write_with(6, |region| {
369 region[..3].copy_from_slice(b"abc");
370 3
371 });
372 assert_eq!(out, b"xabc");
373 }
374
375 #[test]
376 fn vec_write_with_zeroes_the_region() {
377 let mut out = Vec::new();
378 out.write_with(8, |region| {
379 region.iter_mut().for_each(|slot| *slot = b'a');
380 8
381 });
382 out.truncate(4);
383 out.write_with(8, |region| {
384 assert!(region.iter().all(|byte| *byte == 0));
385 0
386 });
387 assert_eq!(out, b"aaaa");
388 }
389
390 #[test]
391 fn default_write_with_matches_the_vec_implementation() {
392 struct Plain(Vec<u8>);
393 impl Writer for Plain {
394 fn write(&mut self, bytes: &[u8]) {
395 self.0.extend_from_slice(bytes);
396 }
397 }
398
399 let mut plain = Plain(Vec::new());
400 plain.write_byte(b'a');
401 plain.write_with(6, |region| {
402 region.iter_mut().for_each(|slot| *slot = b'b');
403 4
404 });
405 assert_eq!(plain.0, b"abbbb");
406 }
407}