Skip to content
This repository was archived by the owner on Feb 14, 2023. It is now read-only.

Commit 7e92eda

Browse files
committed
0.8.0: loosen trait bounds, provide immutable policy accessors, thread-local handler for failed drop-flushes
1 parent 18345c5 commit 7e92eda

File tree

2 files changed

+75
-31
lines changed

2 files changed

+75
-31
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "buf_redux"
3-
version = "0.7.1"
3+
version = "0.8.0"
44
authors = ["Austin Bonander <austin.bonander@gmail.com>"]
55

66
description = "Drop-in replacements for buffered I/O in `std::io` with extra features."

src/lib.rs

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ extern crate memchr;
143143
extern crate safemem;
144144

145145
use std::any::Any;
146+
use std::cell::RefCell;
146147
use std::io::prelude::*;
147148
use std::io::SeekFrom;
148149
use std::{cmp, error, fmt, io, mem, ptr};
@@ -196,7 +197,7 @@ const DEFAULT_BUF_SIZE: usize = 8 * 1024;
196197
/// [`new_ringbuf()`]: BufReader::new_ringbuf
197198
/// [`with_capacity_ringbuf()`]: BufReader::with_capacity_ringbuf
198199
/// [ringbufs-root]: index.html#ringbuffers--slice-deque-feature
199-
pub struct BufReader<R, P: ReaderPolicy = StdPolicy>{
200+
pub struct BufReader<R, P = StdPolicy>{
200201
// First field for null pointer optimization.
201202
buf: Buffer,
202203
inner: R,
@@ -265,27 +266,32 @@ impl<R> BufReader<R, StdPolicy> {
265266
}
266267
}
267268

268-
impl<R, P: ReaderPolicy> BufReader<R, P> {
269+
impl<R, P> BufReader<R, P> {
269270
/// Apply a new `ReaderPolicy` to this `BufReader`, returning the transformed type.
270271
pub fn set_policy<P_: ReaderPolicy>(self, policy: P_) -> BufReader<R, P_> {
271-
BufReader {
272+
BufReader {
272273
inner: self.inner,
273274
buf: self.buf,
274275
policy
275276
}
276277
}
277278

278-
/// Accessor for updating the `ReaderPolicy` in-place.
279+
/// Mutate the current [`ReaderPolicy`](policy::ReaderPolicy) in-place.
279280
///
280281
/// If you want to change the type, use `.set_policy()`.
281282
pub fn policy_mut(&mut self) -> &mut P { &mut self.policy }
282283

284+
/// Inspect the current `ReaderPolicy`.
285+
pub fn policy(&self) -> &P {
286+
&self.policy
287+
}
288+
283289
/// Move data to the start of the buffer, making room at the end for more
284290
/// reading.
285291
///
286292
/// This is a no-op with the `*_ringbuf()` constructors (requires `slice-deque` feature).
287293
pub fn make_room(&mut self) {
288-
self.buf.make_room();
294+
self.buf.make_room();
289295
}
290296

291297
/// Ensure room in the buffer for *at least* `additional` bytes. May not be
@@ -343,14 +349,16 @@ impl<R, P: ReaderPolicy> BufReader<R, P> {
343349
buf: Some(self.buf),
344350
}
345351
}
352+
}
346353

354+
impl<R, P: ReaderPolicy> BufReader<R, P> {
347355
#[inline]
348356
fn should_read(&mut self) -> bool {
349357
self.policy.before_read(&mut self.buf).0
350358
}
351359
}
352360

353-
impl<R: Read, P: ReaderPolicy> BufReader<R, P> {
361+
impl<R: Read, P> BufReader<R, P> {
354362
/// Unconditionally perform a read into the buffer.
355363
///
356364
/// Does not invoke `ReaderPolicy` methods.
@@ -406,7 +414,7 @@ impl<R: Read, P: ReaderPolicy> BufRead for BufReader<R, P> {
406414
}
407415
}
408416

409-
impl<R: fmt::Debug, P: ReaderPolicy + fmt::Debug> fmt::Debug for BufReader<R, P> {
417+
impl<R: fmt::Debug, P: fmt::Debug> fmt::Debug for BufReader<R, P> {
410418
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
411419
fmt.debug_struct("buf_redux::BufReader")
412420
.field("reader", &self.inner)
@@ -485,7 +493,7 @@ impl<R: Seek, P: ReaderPolicy> Seek for BufReader<R, P> {
485493
/// [`new_ringbuf()`]: BufWriter::new_ringbuf
486494
/// [`with_capacity_ringbuf()`]: BufWriter::with_capacity_ringbuf
487495
/// [ringbufs-root]: index.html#ringbuffers--slice-deque-feature
488-
pub struct BufWriter<W: Write, P: WriterPolicy = StdPolicy> {
496+
pub struct BufWriter<W: Write, P = StdPolicy> {
489497
buf: Buffer,
490498
inner: W,
491499
policy: P,
@@ -553,7 +561,7 @@ impl<W: Write> BufWriter<W> {
553561
}
554562
}
555563

556-
impl<W: Write, P: WriterPolicy> BufWriter<W, P> {
564+
impl<W: Write, P> BufWriter<W, P> {
557565
/// Set a new [`WriterPolicy`](policy::WriterPolicy), returning the transformed type.
558566
pub fn set_policy<P_: WriterPolicy>(self, policy: P_) -> BufWriter<W, P_> {
559567
let panicked = self.panicked;
@@ -569,6 +577,11 @@ impl<W: Write, P: WriterPolicy> BufWriter<W, P> {
569577
&mut self.policy
570578
}
571579

580+
/// Inspect the current `WriterPolicy`.
581+
pub fn policy(&self) -> &P {
582+
&self.policy
583+
}
584+
572585
/// Get a reference to the inner writer.
573586
pub fn get_ref(&self) -> &W {
574587
&self.inner
@@ -607,22 +620,6 @@ impl<W: Write, P: WriterPolicy> BufWriter<W, P> {
607620
self.buf.make_room();
608621
}
609622

610-
/// Flush the buffer and unwrap, returning the inner writer on success,
611-
/// or a type wrapping `self` plus the error otherwise.
612-
pub fn into_inner(mut self) -> Result<W, IntoInnerError<Self>> {
613-
match self.flush() {
614-
Err(e) => Err(IntoInnerError(self, e)),
615-
Ok(()) => Ok(self.into_inner_().0),
616-
}
617-
}
618-
619-
/// Flush the buffer and unwrap, returning the inner writer and
620-
/// any error encountered during flushing.
621-
pub fn into_inner_with_err(mut self) -> (W, Option<io::Error>) {
622-
let err = self.flush().err();
623-
(self.into_inner_().0, err)
624-
}
625-
626623
/// Consume `self` and return both the underlying writer and the buffer
627624
pub fn into_inner_with_buffer(self) -> (W, Buffer) {
628625
self.into_inner_()
@@ -649,6 +646,24 @@ impl<W: Write, P: WriterPolicy> BufWriter<W, P> {
649646
}
650647
}
651648

649+
impl<W: Write, P: WriterPolicy> BufWriter<W, P> {
650+
/// Flush the buffer and unwrap, returning the inner writer on success,
651+
/// or a type wrapping `self` plus the error otherwise.
652+
pub fn into_inner(mut self) -> Result<W, IntoInnerError<Self>> {
653+
match self.flush() {
654+
Err(e) => Err(IntoInnerError(self, e)),
655+
Ok(()) => Ok(self.into_inner_().0),
656+
}
657+
}
658+
659+
/// Flush the buffer and unwrap, returning the inner writer and
660+
/// any error encountered during flushing.
661+
pub fn into_inner_with_err(mut self) -> (W, Option<io::Error>) {
662+
let err = self.flush().err();
663+
(self.into_inner_().0, err)
664+
}
665+
}
666+
652667
impl<W: Write, P: WriterPolicy> Write for BufWriter<W, P> {
653668
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
654669
let flush_amt = self.policy.before_write(&mut self.buf, buf.len()).0;
@@ -686,7 +701,7 @@ impl<W: Write + Seek, P: WriterPolicy> Seek for BufWriter<W, P> {
686701
}
687702
}
688703

689-
impl<W: fmt::Debug + Write, P: WriterPolicy + fmt::Debug> fmt::Debug for BufWriter<W, P> {
704+
impl<W: Write + fmt::Debug, P: fmt::Debug> fmt::Debug for BufWriter<W, P> {
690705
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
691706
f.debug_struct("buf_redux::BufWriter")
692707
.field("writer", &self.inner)
@@ -696,11 +711,21 @@ impl<W: fmt::Debug + Write, P: WriterPolicy + fmt::Debug> fmt::Debug for BufWrit
696711
}
697712
}
698713

699-
impl<W: Write, P: WriterPolicy> Drop for BufWriter<W, P> {
714+
715+
/// Attempt to flush the buffer to the underlying writer.
716+
///
717+
/// If an error occurs, the thread-local handler is invoked, if one was previously
718+
/// set by [`set_drop_err_handler`](set_drop_err_handler) for this thread.
719+
impl<W: Write, P> Drop for BufWriter<W, P> {
700720
fn drop(&mut self) {
701721
if !self.panicked {
702-
// dtors should not panic, so we ignore a failed flush
703-
let _r = self.flush();
722+
// instead of ignoring a failed flush, call the handler
723+
let buf_len = self.buf.len();
724+
if let Err(err) = self.flush_buf(buf_len) {
725+
DROP_ERR_HANDLER.with(|deh| {
726+
(*deh.borrow())(&mut self.inner, &mut self.buf, err)
727+
});
728+
}
704729
}
705730
}
706731
}
@@ -801,7 +826,7 @@ impl<W: Write> Write for LineWriter<W> {
801826
}
802827
}
803828

804-
impl<W: fmt::Debug + Write> fmt::Debug for LineWriter<W> {
829+
impl<W: Write + fmt::Debug> fmt::Debug for LineWriter<W> {
805830
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
806831
f.debug_struct("buf_redux::LineWriter")
807832
.field("writer", self.get_ref())
@@ -1239,6 +1264,25 @@ pub fn copy_buf<B: BufRead, W: Write>(b: &mut B, w: &mut W) -> io::Result<u64> {
12391264
Ok(total_copied)
12401265
}
12411266

1267+
thread_local!(
1268+
static DROP_ERR_HANDLER: RefCell<Box<Fn(&mut Write, &mut Buffer, io::Error)>>
1269+
= RefCell::new(Box::new(|_, _, _| ()))
1270+
);
1271+
1272+
/// Set a thread-local handler for errors thrown in `BufWriter`'s `Drop` impl.
1273+
///
1274+
/// The `Write` impl, buffer (at the time of the erroring write) and IO error are provided.
1275+
///
1276+
/// Replaces the previous handler. By default this is a no-op.
1277+
///
1278+
/// ### Panics
1279+
/// If called from within a handler previously provided to this function.
1280+
pub fn set_drop_err_handler<F: 'static>(handler: F)
1281+
where F: Fn(&mut Write, &mut Buffer, io::Error)
1282+
{
1283+
DROP_ERR_HANDLER.with(|deh| *deh.borrow_mut() = Box::new(handler))
1284+
}
1285+
12421286
#[cfg(not(feature = "nightly"))]
12431287
fn init_buffer<R: Read + ?Sized>(_r: &R, buf: &mut [u8]) {
12441288
// we can't trust a reader without nightly

0 commit comments

Comments
 (0)