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
138
139
use std::{cmp::min, io};

use super::{ReadAt, Size, WriteAt};

/// A window into another `ReadAt` or `WriteAt`.
///
/// Given an existing positioned I/O, this presents a limited view of it.
///
/// # Examples
///
/// Some slices have size restrictions:
///
/// ```rust
/// # use std::io;
/// use positioned_io::{ReadAt, Slice};
///
/// # fn foo() -> io::Result<()> {
/// let a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
/// let slice = Slice::new(&a[..], 4, Some(4));
///
/// let mut buf = [0; 4];
/// let bytes = slice.read_at(2, &mut buf)?;
/// assert_eq!(bytes, 2);
/// assert_eq!(buf, [6, 7, 0, 0]);
/// # Ok(())
/// # }
/// # fn main() { foo().unwrap(); }
/// ```
///
/// Some slices do not:
///
/// ```rust
/// # use std::io;
/// use positioned_io::{WriteAt, Slice};
///
/// # fn foo() -> io::Result<()> {
/// let mut v = vec![0, 1, 2, 3, 4, 5];
/// let buf = [9; 3];
///
/// {
///     let mut slice = Slice::new(&mut v, 2, None);
///     slice.write_all_at(3, &buf)?;
/// }
///
/// // The write goes right past the end.
/// assert_eq!(v, vec![0, 1, 2, 3, 4, 9, 9, 9]);
/// # Ok(())
/// # }
/// # fn main() { foo().unwrap(); }
/// ```
#[derive(Debug, Clone)]
pub struct Slice<I> {
    io: I,
    offset: u64,
    size: Option<u64>,
}

impl<I> Slice<I> {
    /// Create a new `Slice`.
    ///
    /// The slice will be a view of `size` bytes, starting at `offset` in `io`.
    /// If you do not pass a size, the size won't be limited.
    pub fn new(io: I, offset: u64, size: Option<u64>) -> Self {
        Slice { io, offset, size }
    }

    /// Get the available bytes starting at some point.
    fn avail(&self, pos: u64, bytes: usize) -> usize {
        match self.size {
            None => bytes,
            Some(size) if pos >= size => 0,
            Some(size) => min(bytes as u64, size - pos) as usize,
        }
    }

    /// Consumes the slice, returning the underlying value.
    pub fn into_inner(self) -> I {
        self.io
    }
    /// Get a reference to the underlying value in this slice.
    ///
    /// Note that IO on the returned value may escape the slice.
    pub fn get_ref(&self) -> &I {
        &self.io
    }
    /// Get a mutable reference to the underlying value in this slice.
    ///
    /// Note that IO on the returned value may escape the slice.
    pub fn get_mut(&mut self) -> &mut I {
        &mut self.io
    }
    /// Get the offset that this slice starts at within the underlying IO.
    pub fn offset(&self) -> u64 {
        self.offset
    }
    /// Set the offset that this slice starts at within the underlying IO.
    pub fn set_offset(&mut self, offset: u64) {
        self.offset = offset
    }
}
impl<I: Size> Slice<I> {
    /// Create a new `Slice` that goes to the end of `io`.
    ///
    /// Note that you can create a larger slice by passing a larger size to
    /// `new()`, but it won't do you any good for reading.
    pub fn new_to_end(io: I, offset: u64) -> io::Result<Self> {
        match io.size() {
            Ok(Some(size)) => Ok(Self::new(io, offset, Some(size - offset))),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "unknown base size",
            )),
        }
    }
}

impl<I: ReadAt> ReadAt for Slice<I> {
    fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
        let bytes = self.avail(pos, buf.len());
        self.io.read_at(pos + self.offset, &mut buf[..bytes])
    }
}

impl<I: WriteAt> WriteAt for Slice<I> {
    fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
        let bytes = self.avail(pos, buf.len());
        self.io.write_at(pos + self.offset, &buf[..bytes])
    }

    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

impl<I> Size for Slice<I> {
    fn size(&self) -> io::Result<Option<u64>> {
        Ok(self.size)
    }
}