Skip to main content

wincode/io/
std_read.rs

1use {
2    crate::io::{BorrowKind, ReadResult, Reader, read_size_limit, slice::SliceScopedUnchecked},
3    core::{mem::MaybeUninit, ptr::copy_nonoverlapping},
4    std::io::{self, BufReader, Cursor, Read},
5};
6
7/// [`Reader`] adapter over any [`std::io::Read`] source.
8///
9/// Wraps any `R: std::io::Read` and exposes it as a wincode [`Reader`], allowing
10/// deserialization from files, network streams, or other I/O sources.
11///
12/// # Examples
13///
14/// Deserialize a tuple via [`ReadAdapter`]:
15///
16/// ```
17/// use wincode::io::std_read::ReadAdapter;
18///
19/// let tuple = (42u32, true, 1234567890i64);
20/// let buf = wincode::serialize(&tuple).unwrap();
21/// let reader = ReadAdapter::new(&buf[..]);
22/// let out: (u32, bool, i64) = wincode::deserialize_from(reader).unwrap();
23/// assert_eq!(out, tuple);
24/// ```
25pub struct ReadAdapter<R: ?Sized>(R);
26
27impl<R: Read> ReadAdapter<R> {
28    pub fn new(inner: R) -> Self {
29        Self(inner)
30    }
31}
32
33#[inline]
34fn copy_into_slice<R: Read + ?Sized>(reader: &mut R, dst: &mut [u8]) -> ReadResult<()> {
35    #[cold]
36    fn maybe_eof_to_read_size_limit(err: io::Error, len: usize) -> ReadResult<()> {
37        if err.kind() == io::ErrorKind::UnexpectedEof {
38            Err(read_size_limit(len))
39        } else {
40            Err(err.into())
41        }
42    }
43    if let Err(e) = reader.read_exact(dst) {
44        return maybe_eof_to_read_size_limit(e, dst.len());
45    };
46    Ok(())
47}
48
49unsafe impl<R: Read + ?Sized> Reader<'_> for ReadAdapter<R> {
50    #[inline(always)]
51    fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
52        copy_into_slice(&mut self.0, dst)
53    }
54}
55
56unsafe impl<R: Read + ?Sized> Reader<'_> for BufReader<R> {
57    #[inline(always)]
58    fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
59        copy_into_slice(self, dst)
60    }
61}
62
63#[inline]
64fn cursor_advance(cursor: &mut Cursor<impl AsRef<[u8]>>, n: usize) -> ReadResult<&[u8]> {
65    let Ok(pos) = usize::try_from(cursor.position()) else {
66        return Err(read_size_limit(usize::MAX));
67    };
68
69    let inner = cursor.get_ref().as_ref();
70    let next_pos = pos.saturating_add(n);
71    if next_pos > inner.len() {
72        return Err(read_size_limit(n));
73    }
74
75    cursor.set_position(next_pos as u64);
76    let inner = cursor.get_ref().as_ref();
77    Ok(&inner[pos..next_pos])
78}
79
80unsafe impl<'a, T> Reader<'a> for Cursor<T>
81where
82    T: AsRef<[u8]>,
83{
84    const BORROW_KINDS: u8 = BorrowKind::CallSite.mask();
85
86    #[inline]
87    fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
88        let src = cursor_advance(self, dst.len())?;
89        // SAFETY:
90        // - `cursor_advance` guarantees that `src` is exactly `dst.len()` bytes.
91        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap
92        //   with the internal buffer.
93        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), dst.len()) };
94        Ok(())
95    }
96
97    #[inline]
98    fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
99        let src = cursor_advance(self, dst.len())?;
100        // SAFETY:
101        // - `cursor_advance` guarantees that `src` is exactly `dst.len()` bytes.
102        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap
103        //   with the internal buffer.
104        unsafe { copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast::<u8>(), dst.len()) };
105        Ok(())
106    }
107
108    #[inline(always)]
109    fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
110        let src = cursor_advance(self, N)?;
111        // SAFETY:
112        // - `cursor_advance` guarantees that `src` is exactly `dst.len()` bytes.
113        // - Given Rust's aliasing rules, we can assume that `dst` does not overlap
114        //   with the internal buffer.
115        Ok(unsafe { *(src.as_ptr().cast::<[u8; N]>()) })
116    }
117
118    #[inline]
119    fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
120        cursor_advance(self, len)
121    }
122
123    #[inline]
124    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult<impl Reader<'a>> {
125        let buf = cursor_advance(self, n_bytes)?;
126        // SAFETY: by calling `as_trusted_for`, caller guarantees they
127        // will will not read beyond the bounds of the slice, `n_bytes`.
128        Ok(unsafe { SliceScopedUnchecked::new(buf) })
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    /// A safe `Read` implementation that inspects the destination before writing.
137    ///
138    /// This catches adapters passing uninitialized storage to `Read::read`: inspecting
139    /// such storage would trigger undefined behavior under Miri.
140    struct InspectingReader {
141        data: Vec<u8>,
142        pos: usize,
143        observed: Vec<u8>,
144    }
145
146    impl InspectingReader {
147        fn new(data: Vec<u8>) -> Self {
148            Self {
149                data,
150                pos: 0,
151                observed: Vec::new(),
152            }
153        }
154    }
155
156    impl Read for InspectingReader {
157        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
158            self.observed.extend_from_slice(dst);
159
160            let remaining = &self.data[self.pos..];
161            let len = dst.len().min(remaining.len());
162            dst[..len].copy_from_slice(&remaining[..len]);
163            self.pos = self.pos.checked_add(len).unwrap();
164            Ok(len)
165        }
166    }
167
168    #[test]
169    fn read_adapter_initializes_destination_before_reading() {
170        let expected = 0x0123_4567_89ab_cdef_u64;
171        let data = crate::serialize(&expected).unwrap();
172        let mut reader = InspectingReader::new(data.clone());
173
174        let actual: u64 = crate::deserialize_from(ReadAdapter::new(&mut reader)).unwrap();
175
176        assert_eq!(actual, expected);
177        assert_eq!(reader.observed, vec![0; data.len()]);
178    }
179
180    #[test]
181    fn buf_reader_initializes_destination_before_reading() {
182        let expected = 0x0123_4567_89ab_cdef_u64;
183        let data = crate::serialize(&expected).unwrap();
184        let mut reader = InspectingReader::new(data.clone());
185
186        let actual: u64 =
187            crate::deserialize_from(BufReader::with_capacity(1, &mut reader)).unwrap();
188
189        assert_eq!(actual, expected);
190        assert_eq!(reader.observed, vec![0; data.len()]);
191    }
192}