1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Utility functions for the [`Skip`] trait.

use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader, Read, Seek};
use std::io::{Cursor, Empty};

use crate::{SeekSkipAdapter, Skip};

//
// Skip impls
//

macro_rules! deref_skip {
    () => {
        fn skip(&mut self, amount: u64) -> io::Result<()> {
            (**self).skip(amount)
        }

        fn stream_position(&mut self) -> io::Result<u64> {
            (**self).stream_position()
        }

        fn stream_len(&mut self) -> io::Result<u64> {
            (**self).stream_len()
        }
    };
}

impl<T: Skip + ?Sized> Skip for &mut T {
    deref_skip!();
}

impl<T: Skip + ?Sized> Skip for Box<T> {
    deref_skip!();
}

macro_rules! skip_via_adapter {
    () => {
        fn skip(&mut self, amount: u64) -> io::Result<()> {
            SeekSkipAdapter(self).skip(amount)
        }

        fn stream_position(&mut self) -> io::Result<u64> {
            SeekSkipAdapter(self).stream_position()
        }

        fn stream_len(&mut self) -> io::Result<u64> {
            SeekSkipAdapter(self).stream_len()
        }
    };
}

impl<T: AsRef<[u8]>> Skip for Cursor<T> {
    skip_via_adapter!();
}

impl Skip for Empty {
    skip_via_adapter!();
}

impl Skip for File {
    skip_via_adapter!();
}

impl Skip for &File {
    skip_via_adapter!();
}

impl<T: Read + Skip + ?Sized> Skip for BufReader<T> {
    fn skip(&mut self, amount: u64) -> io::Result<()> {
        let buf_len = self.buffer().len();
        if let Some(skip_amount) = amount.checked_sub(buf_len as u64) {
            if skip_amount != 0 {
                self.get_mut().skip(skip_amount)?;
            }
        }
        self.consume(buf_len.min(amount as usize));
        Ok(())
    }

    /// Return the stream position for a [`BufReader`] implementing [`Read`] + [`Skip`].
    fn stream_position(&mut self) -> io::Result<u64> {
        let stream_pos = self.get_mut().stream_position()?;
        Ok(stream_pos.saturating_sub(self.buffer().len() as u64))
    }

    /// Return the stream length for a [`BufReader`] implementing [`Read`] + [`Skip`].
    fn stream_len(&mut self) -> io::Result<u64> {
        self.get_mut().stream_len()
    }
}

//
// SeekSkipAdapter impls
//

impl<T: Seek> Skip for SeekSkipAdapter<T> {
    fn skip(&mut self, amount: u64) -> io::Result<()> {
        match amount.try_into() {
            Ok(0) => (),
            Ok(amount) => {
                self.seek(io::SeekFrom::Current(amount))?;
            }
            Err(_) => {
                let stream_pos = self.stream_position()?;
                let seek_pos = stream_pos
                    .checked_add(amount)
                    .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "seek past u64::MAX"))?;
                self.seek(io::SeekFrom::Start(seek_pos))?;
            }
        }
        Ok(())
    }

    fn stream_position(&mut self) -> io::Result<u64> {
        self.0.stream_position()
    }

    fn stream_len(&mut self) -> io::Result<u64> {
        // This is the unstable Seek::stream_len
        let stream_pos = self.stream_position()?;
        let len = self.0.seek(io::SeekFrom::End(0))?;

        if stream_pos != len {
            self.0.seek(io::SeekFrom::Start(stream_pos))?;
        }

        Ok(len)
    }
}

impl<T: Read + ?Sized> Read for SeekSkipAdapter<T> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}