partial_io/write.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
// Copyright (c) The partial-io Contributors
// SPDX-License-Identifier: MIT
//! This module contains a writer wrapper that breaks writes up according to a
//! provided iterator.
use std::{
cmp, fmt,
io::{self, Read, Write},
};
use crate::{make_ops, PartialOp};
/// A writer wrapper that breaks inner `Write` instances up according to the
/// provided iterator.
///
/// # Examples
///
/// ```rust
/// use std::io::Write;
///
/// use partial_io::{PartialOp, PartialWrite};
///
/// let writer = Vec::new();
/// let iter = ::std::iter::repeat(PartialOp::Limited(1));
/// let mut partial_writer = PartialWrite::new(writer, iter);
/// let in_data = vec![1, 2, 3, 4];
///
/// let size = partial_writer.write(&in_data).unwrap();
/// assert_eq!(size, 1);
/// assert_eq!(&partial_writer.get_ref()[..], &[1]);
/// ```
pub struct PartialWrite<W> {
inner: W,
ops: Box<dyn Iterator<Item = PartialOp> + Send>,
}
impl<W> PartialWrite<W>
where
W: Write,
{
/// Creates a new `PartialWrite` wrapper over the writer with the specified `PartialOp`s.
pub fn new<I>(inner: W, iter: I) -> Self
where
I: IntoIterator<Item = PartialOp> + 'static,
I::IntoIter: Send,
{
PartialWrite {
inner,
// Use fuse here so that we don't keep calling the inner iterator
// once it's returned None.
ops: make_ops(iter),
}
}
/// Sets the `PartialOp`s for this writer.
pub fn set_ops<I>(&mut self, iter: I) -> &mut Self
where
I: IntoIterator<Item = PartialOp> + 'static,
I::IntoIter: Send,
{
self.ops = make_ops(iter);
self
}
/// Acquires a reference to the underlying writer.
pub fn get_ref(&self) -> &W {
&self.inner
}
/// Acquires a mutable reference to the underlying writer.
pub fn get_mut(&mut self) -> &mut W {
&mut self.inner
}
/// Consumes this wrapper, returning the underlying writer.
pub fn into_inner(self) -> W {
self.inner
}
}
impl<W> Write for PartialWrite<W>
where
W: Write,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self.ops.next() {
Some(PartialOp::Limited(n)) => {
let len = cmp::min(n, buf.len());
self.inner.write(&buf[..len])
}
Some(PartialOp::Err(err)) => Err(io::Error::new(
err,
"error during write, generated by partial-io",
)),
Some(PartialOp::Unlimited) | None => self.inner.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match self.ops.next() {
Some(PartialOp::Err(err)) => Err(io::Error::new(
err,
"error during flush, generated by partial-io",
)),
_ => self.inner.flush(),
}
}
}
// Forwarding impl to support duplex structs.
impl<W> Read for PartialWrite<W>
where
W: Read + Write,
{
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
impl<W> fmt::Debug for PartialWrite<W>
where
W: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PartialWrite")
.field("inner", &self.inner)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use crate::tests::assert_send;
#[test]
fn test_sendable() {
assert_send::<PartialWrite<File>>();
}
}