alice_protocol_reader/
stdin_reader.rs

1//! Wrapper for a reader, implements [BufferedReaderWrapper].
2//!
3//! The wrapper can wrap both [BufReader](io::BufReader) and [StdInReaderSeeker].
4//! Needed because [Stdin](io::Stdin) does not implement seek_relative, and this serves as a convenient way to skip unwanted data.
5//! seek_relative is used to skip over unwanted bytes in the input stream, such as links unwanted by the user
6use super::bufreader_wrapper::BufferedReaderWrapper;
7use std::io::{self, Read, SeekFrom};
8
9/// Wrapper for a reader where input data can be read from, implements [BufferedReaderWrapper].
10#[derive(Debug)]
11pub struct StdInReaderSeeker<R> {
12    /// Generic reader that is wrapped
13    pub reader: R,
14}
15
16/// Specialization for [io::Stdin]
17impl BufferedReaderWrapper for StdInReaderSeeker<io::Stdin> {
18    fn seek_relative_offset(&mut self, offset: i64) -> io::Result<()> {
19        // Seeking is not supported in stdin, so we have to read the bytes and discard them
20        let mut buf = vec![0; offset as usize];
21        match io::stdin().lock().read_exact(&mut buf) {
22            Ok(_) => Ok(()),
23            // If we're seeking the offset amount and reached an unexpected EOF then it's possible that the offset retrieved from the RDH is wrong
24            Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
25                // Seeking past EOF is InvalidInput in this case
26                Err(io::Error::new(
27                io::ErrorKind::InvalidInput,
28                format!("Failed to read and discard a payload from stdin of size {offset} (according to previously loaded RDH): {e}"),
29            ))
30            }
31            Err(e) => Err(e),
32        }
33    }
34}
35
36impl io::Read for StdInReaderSeeker<io::Stdin> {
37    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
38        self.reader.lock().read(buf)
39    }
40}
41impl io::Seek for StdInReaderSeeker<io::Stdin> {
42    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
43        match pos {
44            SeekFrom::Start(_) => Err(io::Error::new(
45                io::ErrorKind::Other,
46                "Cannot seek from start in stdin",
47            )),
48            SeekFrom::Current(_) | SeekFrom::End(_) => {
49                debug_assert!(
50                    false,
51                    "Seeking from current or end in stdin is not supported"
52                );
53                unsafe { std::hint::unreachable_unchecked() }
54            }
55        }
56    }
57}