mediasan_common/
skip.rs

1//! Utility functions for the [`Skip`] trait.
2
3use std::fs::File;
4use std::io;
5use std::io::{BufRead, BufReader, Read, Seek};
6use std::io::{Cursor, Empty};
7
8use crate::{SeekSkipAdapter, Skip};
9
10//
11// Skip impls
12//
13
14macro_rules! deref_skip {
15    () => {
16        fn skip(&mut self, amount: u64) -> io::Result<()> {
17            (**self).skip(amount)
18        }
19
20        fn stream_position(&mut self) -> io::Result<u64> {
21            (**self).stream_position()
22        }
23
24        fn stream_len(&mut self) -> io::Result<u64> {
25            (**self).stream_len()
26        }
27    };
28}
29
30impl<T: Skip + ?Sized> Skip for &mut T {
31    deref_skip!();
32}
33
34impl<T: Skip + ?Sized> Skip for Box<T> {
35    deref_skip!();
36}
37
38macro_rules! skip_via_adapter {
39    () => {
40        fn skip(&mut self, amount: u64) -> io::Result<()> {
41            SeekSkipAdapter(self).skip(amount)
42        }
43
44        fn stream_position(&mut self) -> io::Result<u64> {
45            SeekSkipAdapter(self).stream_position()
46        }
47
48        fn stream_len(&mut self) -> io::Result<u64> {
49            SeekSkipAdapter(self).stream_len()
50        }
51    };
52}
53
54impl<T: AsRef<[u8]>> Skip for Cursor<T> {
55    skip_via_adapter!();
56}
57
58impl Skip for Empty {
59    skip_via_adapter!();
60}
61
62impl Skip for File {
63    skip_via_adapter!();
64}
65
66impl Skip for &File {
67    skip_via_adapter!();
68}
69
70impl<T: Read + Skip + ?Sized> Skip for BufReader<T> {
71    fn skip(&mut self, amount: u64) -> io::Result<()> {
72        let buf_len = self.buffer().len();
73        if let Some(skip_amount) = amount.checked_sub(buf_len as u64) {
74            if skip_amount != 0 {
75                self.get_mut().skip(skip_amount)?;
76            }
77        }
78        self.consume(buf_len.min(amount as usize));
79        Ok(())
80    }
81
82    /// Return the stream position for a [`BufReader`] implementing [`Read`] + [`Skip`].
83    fn stream_position(&mut self) -> io::Result<u64> {
84        let stream_pos = self.get_mut().stream_position()?;
85        Ok(stream_pos.saturating_sub(self.buffer().len() as u64))
86    }
87
88    /// Return the stream length for a [`BufReader`] implementing [`Read`] + [`Skip`].
89    fn stream_len(&mut self) -> io::Result<u64> {
90        self.get_mut().stream_len()
91    }
92}
93
94//
95// SeekSkipAdapter impls
96//
97
98impl<T: Seek> Skip for SeekSkipAdapter<T> {
99    fn skip(&mut self, amount: u64) -> io::Result<()> {
100        match amount.try_into() {
101            Ok(0) => (),
102            Ok(amount) => {
103                self.seek(io::SeekFrom::Current(amount))?;
104            }
105            Err(_) => {
106                let stream_pos = self.stream_position()?;
107                let seek_pos = stream_pos
108                    .checked_add(amount)
109                    .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "seek past u64::MAX"))?;
110                self.seek(io::SeekFrom::Start(seek_pos))?;
111            }
112        }
113        Ok(())
114    }
115
116    fn stream_position(&mut self) -> io::Result<u64> {
117        self.0.stream_position()
118    }
119
120    fn stream_len(&mut self) -> io::Result<u64> {
121        // This is the unstable Seek::stream_len
122        let stream_pos = self.stream_position()?;
123        let len = self.0.seek(io::SeekFrom::End(0))?;
124
125        if stream_pos != len {
126            self.0.seek(io::SeekFrom::Start(stream_pos))?;
127        }
128
129        Ok(len)
130    }
131}
132
133impl<T: Read + ?Sized> Read for SeekSkipAdapter<T> {
134    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
135        self.0.read(buf)
136    }
137}