Skip to main content

compio_buf/
io.rs

1use std::{io, marker::PhantomData};
2
3use crate::{IntoInner, IoBuf, IoBufMut, Slice};
4
5/// Adapts an [`IoBuf`] to implement the [`std::io::Read`] trait.
6///
7/// This can be constructed with [`IoBuf::into_reader`]
8pub struct Reader<B>(Slice<B>);
9
10impl<B> Reader<B> {
11    /// Creates a new [`Reader`] from the given buffer.
12    pub fn new(buf: B) -> Self
13    where
14        B: IoBuf,
15    {
16        Self(buf.slice(..))
17    }
18
19    /// Returns a reference to the inner buffer.
20    pub fn as_inner(&self) -> &B {
21        self.0.as_inner()
22    }
23
24    /// Returns a mutable reference to the inner buffer.
25    pub fn as_inner_mut(&mut self) -> &mut B {
26        self.0.as_inner_mut()
27    }
28
29    /// Returns the number of bytes that have been read so far.
30    pub fn progress(&self) -> usize {
31        self.0.begin()
32    }
33}
34
35impl<B: IoBuf> Reader<B> {
36    /// Returns the remaining bytes to be read.
37    pub fn as_remaining(&self) -> &[u8] {
38        &self.0
39    }
40
41    /// Consumes the reader and returns the remaining bytes to be read.
42    pub fn into_remaining(self) -> Slice<B> {
43        self.0
44    }
45}
46
47impl<B: IoBuf> io::Read for Reader<B> {
48    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
49        let n = self.as_remaining().read(buf)?;
50        self.0.set_begin(self.0.begin() + n);
51        Ok(n)
52    }
53}
54
55impl<B> IntoInner for Reader<B> {
56    type Inner = B;
57
58    fn into_inner(self) -> Self::Inner {
59        self.0.into_inner()
60    }
61}
62
63/// Adapts a reference to [`IoBuf`] to [`std::io::Read`] trait.
64///
65/// This can be constructed with [`IoBuf::as_reader`].
66pub struct ReaderRef<'a, B: ?Sized>(&'a [u8], PhantomData<&'a B>);
67
68impl<'a, B: ?Sized> ReaderRef<'a, B> {
69    /// Creates a new [`ReaderRef`] from the given buffer reference.
70    pub fn new(buf: &'a B) -> Self
71    where
72        B: IoBuf,
73    {
74        Self(buf.as_init(), PhantomData)
75    }
76}
77
78impl<B: IoBuf> io::Read for ReaderRef<'_, B> {
79    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
80        // implementation of Read for &[u8] will update the reference to point after
81        // the read bytes, so we can just delegate to it.
82        self.0.read(buf)
83    }
84}
85
86/// Adapts an [`IoBufMut`] to implement the [`std::io::Write`] trait.
87///
88/// This can be constructed with [`IoBufMut::into_writer`]
89pub struct Writer<B>(B);
90
91impl<B> Writer<B> {
92    /// Creates a new [`Writer`] from the given buffer.
93    pub fn new(buf: B) -> Self {
94        Self(buf)
95    }
96
97    /// Returns a reference to the inner buffer.
98    pub fn as_inner(&self) -> &B {
99        &self.0
100    }
101
102    /// Returns a mutable reference to the inner buffer.
103    pub fn as_inner_mut(&mut self) -> &mut B {
104        &mut self.0
105    }
106}
107
108impl<B: IoBufMut> io::Write for Writer<B> {
109    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
110        match self.0.extend_from_slice(buf) {
111            Ok(_) => Ok(buf.len()),
112            Err(e) => Err(io::Error::other(e)),
113        }
114    }
115
116    fn flush(&mut self) -> io::Result<()> {
117        Ok(())
118    }
119}
120
121impl<B> IntoInner for Writer<B> {
122    type Inner = B;
123
124    fn into_inner(self) -> Self::Inner {
125        self.0
126    }
127}
128
129/// Adapts a mutable reference to [`IoBufMut`] to [`std::io::Write`] trait.
130///
131/// This can be constructed with [`IoBufMut::as_writer`].
132pub struct WriterRef<'a, B: ?Sized>(&'a mut B);
133
134impl<'a, B: ?Sized> WriterRef<'a, B> {
135    /// Creates a new [`WriterRef`] from the given mutable buffer reference.
136    pub fn new(buf: &'a mut B) -> Self {
137        Self(buf)
138    }
139
140    /// Returns a reference to the inner buffer.
141    pub fn as_inner(&self) -> &B {
142        self.0
143    }
144
145    /// Returns a mutable reference to the inner buffer.
146    pub fn as_inner_mut(&mut self) -> &mut B {
147        self.0
148    }
149}
150
151impl<B: IoBufMut + ?Sized> io::Write for WriterRef<'_, B> {
152    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
153        self.0.extend_from_slice(buf)?;
154        Ok(buf.len())
155    }
156
157    fn flush(&mut self) -> io::Result<()> {
158        Ok(())
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use std::io::{Read, Write};
165
166    use super::*;
167
168    #[test]
169    fn reader_tracks_progress_and_remaining() {
170        let data = b"hello".to_vec();
171        let mut reader = Reader::new(data.clone());
172
173        let mut chunk = [0u8; 2];
174        let n = reader.read(&mut chunk).unwrap();
175        assert_eq!(n, 2);
176        assert_eq!(&chunk, b"he");
177        assert_eq!(reader.progress(), 2);
178        assert_eq!(reader.as_remaining(), b"llo");
179
180        let remaining = reader.into_remaining();
181        assert_eq!(&*remaining, b"llo");
182    }
183
184    #[test]
185    fn reader_ref_delegates_reads() {
186        let data = b"readref".to_vec();
187        let mut reader = ReaderRef::new(&data);
188
189        let mut first = [0u8; 4];
190        _ = reader.read(&mut first).unwrap();
191        assert_eq!(&first, b"read");
192
193        let mut second = [0u8; 3];
194        _ = reader.read(&mut second).unwrap();
195        assert_eq!(&second, b"ref");
196    }
197
198    #[test]
199    fn writer_accumulates_bytes() {
200        let mut writer = Writer::new(Vec::new());
201
202        writer.write_all(b"foo").unwrap();
203        writer.write_all(b"bar").unwrap();
204        writer.flush().unwrap();
205
206        assert_eq!(writer.as_inner().as_slice(), b"foobar");
207
208        let inner = writer.into_inner();
209        assert_eq!(inner, b"foobar".to_vec());
210    }
211
212    #[test]
213    fn writer_ref_updates_underlying_buffer() {
214        let mut buf = Vec::new();
215
216        {
217            let mut writer = WriterRef::new(&mut buf);
218            writer.write_all(b"abc").unwrap();
219            writer.write_all(b"123").unwrap();
220            writer.flush().unwrap();
221        }
222
223        assert_eq!(buf, b"abc123");
224    }
225}