system_interface/io/
peek.rs

1use std::fs::File;
2use std::io::{
3    self, BufRead, BufReader, Chain, Cursor, Empty, Read, Repeat, Seek, SeekFrom, StdinLock, Take,
4};
5use std::net::TcpStream;
6#[cfg(unix)]
7use std::os::unix::net::UnixStream;
8
9/// A trait providing the `peek` function for reading without consuming.
10///
11/// Many common `Read` implementations have `Peek` implementations, however
12/// [`Stdin`], [`ChildStderr`], [`ChildStdout`], [`PipeReader`], and
13/// [`CharDevice`] do not, since they are unbuffered and pipes and character
14/// devices don't support any form of peeking.
15///
16/// [`Stdin`]: std::io::Stdin
17/// [`ChildStdout`]: std::process::ChildStdout
18/// [`ChildStderr`]: std::process::ChildStderr
19/// [`PipeReader`]: https://docs.rs/os_pipe/latest/os_pipe/struct.PipeReader.html
20/// [`CharDevice`]: https://docs.rs/char-device/latest/char_device/struct.CharDevice.html
21pub trait Peek {
22    /// Reads data from a stream without consuming it; subsequent reads will
23    /// re-read the data. May return fewer bytes than requested; `Ok(0)`
24    /// indicates that seeking is not possible (but reading may still be).
25    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize>;
26}
27
28impl Peek for File {
29    #[inline]
30    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
31        let pos = self.seek(SeekFrom::Current(0))?;
32        crate::fs::FileIoExt::read_at(self, buf, pos)
33    }
34}
35
36#[cfg(feature = "cap_std_impls")]
37impl Peek for cap_std::fs::File {
38    #[inline]
39    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
40        let pos = self.seek(SeekFrom::Current(0))?;
41        crate::fs::FileIoExt::read_at(self, buf, pos)
42    }
43}
44
45#[cfg(feature = "cap_std_impls_fs_utf8")]
46impl Peek for cap_std::fs_utf8::File {
47    #[inline]
48    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
49        let pos = self.seek(SeekFrom::Current(0))?;
50        crate::fs::FileIoExt::read_at(self, buf, pos)
51    }
52}
53
54impl Peek for TcpStream {
55    #[inline]
56    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
57        TcpStream::peek(self, buf)
58    }
59}
60
61#[cfg(unix)]
62impl Peek for UnixStream {
63    #[inline]
64    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
65        #[cfg(unix_socket_peek)]
66        {
67            UnixStream::peek(self, buf)
68        }
69
70        #[cfg(not(unix_socket_peek))]
71        {
72            // Return the conservatively correct value.
73            let _ = buf;
74            Ok(0)
75        }
76    }
77}
78
79impl Peek for Repeat {
80    #[inline]
81    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
82        // Repeat just reads the same byte repeatedly, so we can just read
83        // from it.
84        self.read(buf)
85    }
86}
87
88#[cfg(feature = "socketpair")]
89impl Peek for socketpair::SocketpairStream {
90    #[inline]
91    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
92        socketpair::SocketpairStream::peek(self, buf)
93    }
94}
95
96impl Peek for Empty {
97    #[inline]
98    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
99        peek_from_bufread(self, buf)
100    }
101}
102
103impl<'a> Peek for &'a [u8] {
104    #[inline]
105    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
106        peek_from_bufread(self, buf)
107    }
108}
109
110impl<'a> Peek for StdinLock<'a> {
111    #[inline]
112    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
113        peek_from_bufread(self, buf)
114    }
115}
116
117impl<B: BufRead + ?Sized> Peek for Box<B> {
118    #[inline]
119    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
120        peek_from_bufread(self, buf)
121    }
122}
123
124impl<'a, B: BufRead + ?Sized> Peek for &'a mut B {
125    #[inline]
126    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
127        peek_from_bufread(self, buf)
128    }
129}
130
131impl<R: Read> Peek for BufReader<R> {
132    #[inline]
133    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
134        peek_from_bufread(self, buf)
135    }
136}
137
138impl<T> Peek for Cursor<T>
139where
140    T: AsRef<[u8]>,
141{
142    #[inline]
143    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
144        peek_from_bufread(self, buf)
145    }
146}
147
148impl<T: BufRead> Peek for Take<T> {
149    #[inline]
150    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
151        peek_from_bufread(self, buf)
152    }
153}
154
155impl<T: BufRead, U: BufRead> Peek for Chain<T, U> {
156    #[inline]
157    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
158        peek_from_bufread(self, buf)
159    }
160}
161
162/// Implement `peek` for types that implement `BufRead`.
163#[inline]
164pub fn peek_from_bufread<BR: BufRead>(buf_read: &mut BR, buf: &mut [u8]) -> io::Result<usize> {
165    // Call `fill_buf` to read the bytes, but don't call `consume`.
166    Read::read(&mut buf_read.fill_buf()?, buf)
167}
168
169#[cfg(feature = "socket2")]
170impl Peek for socket2::Socket {
171    #[inline]
172    fn peek(&mut self, buf: &mut [u8]) -> io::Result<usize> {
173        use io_lifetimes::AsSocketlike;
174        self.as_socketlike_view::<std::net::TcpStream>().peek(buf)
175    }
176}