1use crate::{
2 bounded_reader::{
3 error::BoundedReaderErr as BErr,
4 traits::{Bounded, BoundedIndex, CloneAndRewind},
5 },
6 ensure,
7};
8
9use bytes::Bytes;
10use std::{
11 cmp::min,
12 io::{self, Cursor, Read, Seek, SeekFrom},
13 ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
14};
15
16static RANGE_VALID_QED: &str = "Range is limited to previous valid values .qed";
17
18#[derive(Debug, Clone)]
19pub struct MemBoundedReader {
20 content: Bytes,
21 reader: Cursor<Bytes>,
22}
23
24impl MemBoundedReader {
25 pub fn new(content: Bytes) -> Self {
26 let reader = Cursor::new(content.clone());
27 Self { content, reader }
28 }
29}
30
31impl Read for MemBoundedReader {
32 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
33 self.reader.read(buf)
34 }
35}
36
37impl Seek for MemBoundedReader {
38 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
39 self.reader.seek(pos)
40 }
41}
42
43impl From<Bytes> for MemBoundedReader {
44 fn from(content: Bytes) -> Self {
45 Self::new(content)
46 }
47}
48
49impl Bounded for MemBoundedReader {
50 fn bounds(&self) -> Range<u64> {
51 0u64..self.content.len() as u64
52 }
53
54 fn bound_len(&self) -> u64 {
56 self.content.len() as u64
57 }
58
59 fn sub<R: BoundedIndex<Self>>(&self, range: R) -> Result<Self, BErr> {
61 range.get(self)
62 }
63
64 fn clamped_sub<R: BoundedIndex<Self>>(&self, range: R) -> Self {
65 range.clamped_get(self)
66 }
67}
68
69impl CloneAndRewind for MemBoundedReader {
70 fn clone_and_rewind(&self) -> Self {
71 Self::new(self.content.clone())
72 }
73}
74
75impl BoundedIndex<MemBoundedReader> for Range<u64> {
76 fn get(self, bounded: &MemBoundedReader) -> Result<MemBoundedReader, BErr> {
77 ensure!(self.start <= self.end, BErr::invalid_range(self));
78 ensure!(self.start <= bounded.content.len() as u64, BErr::sub_start_exceed(bounded, self.start));
79 ensure!(self.end <= bounded.content.len() as u64, BErr::sub_end_exceed(bounded, self.end));
80
81 let slice_range = try_into_usize_range(self.start, self.end)?;
82 Ok(MemBoundedReader::new(bounded.content.slice(slice_range)))
83 }
84
85 fn clamped_get(self, bounded: &MemBoundedReader) -> MemBoundedReader {
86 let clamped_start = min(self.start, bounded.content.len() as u64);
87 let clamped_end = min(self.end, bounded.content.len() as u64);
88 let clamped_start = min(clamped_start, clamped_end);
89
90 let slice_range = try_into_usize_range(clamped_start, clamped_end).expect(RANGE_VALID_QED);
91 MemBoundedReader::new(bounded.content.slice(slice_range))
92 }
93}
94
95impl BoundedIndex<MemBoundedReader> for RangeFrom<u64> {
96 fn get(self, bounded: &MemBoundedReader) -> Result<MemBoundedReader, BErr> {
97 ensure!(self.start <= bounded.content.len() as u64, BErr::sub_start_exceed(bounded, self.start));
98
99 let slice_range = try_into_usize(self.start)?..bounded.content.len();
100 Ok(MemBoundedReader::new(bounded.content.slice(slice_range)))
101 }
102
103 fn clamped_get(self, bounded: &MemBoundedReader) -> MemBoundedReader {
104 let clamped_start = min(self.start, bounded.content.len() as u64);
105 let clamped_start = try_into_usize(clamped_start).expect(RANGE_VALID_QED);
106
107 MemBoundedReader::new(bounded.content.slice(clamped_start..bounded.content.len()))
108 }
109}
110
111impl BoundedIndex<MemBoundedReader> for RangeInclusive<u64> {
112 fn get(self, bounded: &MemBoundedReader) -> Result<MemBoundedReader, BErr> {
113 let (start, end) = self.into_inner();
114 let inc_end = end.checked_add(1).ok_or_else(|| BErr::file_too_large(bounded, start, end))?;
115 (start..inc_end).get(bounded)
116 }
117
118 fn clamped_get(self, bounded: &MemBoundedReader) -> MemBoundedReader {
119 let (start, inc_end) = self.into_inner();
120 (start..(inc_end.saturating_add(1))).clamped_get(bounded)
121 }
122}
123
124impl BoundedIndex<MemBoundedReader> for RangeTo<u64> {
125 fn get(self, bounded: &MemBoundedReader) -> Result<MemBoundedReader, BErr> {
126 (0..self.end).get(bounded)
127 }
128
129 fn clamped_get(self, bounded: &MemBoundedReader) -> MemBoundedReader {
130 (0..self.end).clamped_get(bounded)
131 }
132}
133
134impl BoundedIndex<MemBoundedReader> for RangeToInclusive<u64> {
135 fn get(self, bounded: &MemBoundedReader) -> Result<MemBoundedReader, BErr> {
136 let end = self.end.checked_add(1).ok_or_else(|| BErr::file_too_large(bounded, 0, self.end))?;
137 (0..end).get(bounded)
138 }
139
140 fn clamped_get(self, bounded: &MemBoundedReader) -> MemBoundedReader {
141 let end = self.end.saturating_add(1);
142 (0..end).clamped_get(bounded)
143 }
144}
145
146impl BoundedIndex<MemBoundedReader> for RangeFull {
147 fn get(self, bounded: &MemBoundedReader) -> Result<MemBoundedReader, BErr> {
148 Ok(self.clamped_get(bounded))
149 }
150
151 fn clamped_get(self, bounded: &MemBoundedReader) -> MemBoundedReader {
152 MemBoundedReader::new(bounded.content.clone())
153 }
154}
155
156fn try_into_usize(n: u64) -> Result<usize, BErr> {
157 usize::try_from(n).map_err(|_| BErr::range_not_supp(n, 0))
158}
159
160fn try_into_usize_range(start: u64, end: u64) -> Result<Range<usize>, BErr> {
161 let try_err = |_| BErr::range_not_supp(start, end);
162
163 let s = usize::try_from(start).map_err(try_err)?;
164 let e = usize::try_from(end).map_err(try_err)?;
165 Ok(s..e)
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use crate::bounded_reader::traits::{Bounded, BoundedIndex};
172 use bytes::Bytes;
173 use std::io::Read;
174 use test_case::test_case;
175
176 const HELLO: &[u8] = b"Hello world";
177 const LOREM_IPSUM: &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
178
179 #[allow(unused_parens)]
180 #[test_case( HELLO, 0..4 => b"Hell".to_vec(); "From 0 to 4")]
181 #[test_case( HELLO, 2..=4 => b"llo".to_vec(); "From 2 to =4")]
182 #[test_case( HELLO, ..=4 => b"Hello".to_vec(); "to =4")]
183 #[test_case( HELLO, (0..) => b"Hello world".to_vec(); "From 0 to .." )]
184 #[test_case( HELLO, (6..) => b"world".to_vec(); "From 5 to .." )]
185 #[test_case( HELLO, (..) => b"Hello world".to_vec(); "full range" )]
186 fn bounded_index_as_shared<D, R>(data: D, range: R) -> Vec<u8>
187 where
188 D: AsRef<[u8]>,
189 R: BoundedIndex<MemBoundedReader>,
190 {
191 let bounded = MemBoundedReader::new(Bytes::copy_from_slice(data.as_ref()));
192 let mut sub = bounded.sub(range).unwrap();
193
194 let mut sub_content = vec![];
195 let _ = sub.read_to_end(&mut sub_content).unwrap();
196 sub_content
197 }
198
199 #[test_case( LOREM_IPSUM, &[(28..55),(12..22)] => b"adipiscing".to_vec(); "Nested (27..55)(12..22)" )]
200 #[test_case( LOREM_IPSUM, &[(28..55),(0..11)] => b"consectetur".to_vec(); "Nested (27..55)(0..11)" )]
201 #[test_case( LOREM_IPSUM, &[28..=55,23..=26] => b"elit".to_vec(); "Nested 27..=55 23..=26" )]
202 #[test_case( LOREM_IPSUM, &[..=55, ..=4] => b"Lorem".to_vec(); "Nested ..=55 ..=4" )]
203 #[test_case( LOREM_IPSUM, &[(28..), (88..)] => b"aliqua.".to_vec(); "Nested (28..) (88..)" )]
204 #[test_case( LOREM_IPSUM, &[(..), (..)] => LOREM_IPSUM.to_vec(); "Nested (..) (..)" )]
205 fn nested_bounded_index_as_shared<D, R>(data: D, nested_ranges: &[R]) -> Vec<u8>
206 where
207 D: AsRef<[u8]>,
208 R: BoundedIndex<MemBoundedReader> + Clone,
209 {
210 let mut bounded = MemBoundedReader::new(Bytes::copy_from_slice(data.as_ref()));
211 for range in nested_ranges {
212 bounded = bounded.sub(range.clone()).unwrap();
213 }
214
215 let mut content = vec![];
216 let _ = bounded.read_to_end(&mut content).unwrap();
217 content
218 }
219}