1use std::io::{self, Read, Seek, SeekFrom};
46
47use oxideav_core::{BytesSource, Error, Result};
48
49pub struct SubSource {
53 inner: Box<dyn BytesSource>,
54 base: u64,
55 len: u64,
56 pos: u64,
59}
60
61impl SubSource {
62 pub fn new(mut inner: Box<dyn BytesSource>, base: u64, len: u64) -> Result<Self> {
69 let end = base
70 .checked_add(len)
71 .ok_or_else(|| Error::invalid("SubSource: base + len overflows u64"))?;
72 let inner_len = stream_len(&mut inner)
73 .map_err(|e| Error::invalid(format!("SubSource: cannot probe inner length: {e}")))?;
74 if end > inner_len {
75 return Err(Error::invalid(format!(
76 "SubSource: window [{base}, {end}) extends past inner length {inner_len}"
77 )));
78 }
79 inner
80 .seek(SeekFrom::Start(base))
81 .map_err(|e| Error::invalid(format!("SubSource: cannot seek inner to {base}: {e}")))?;
82 Ok(Self {
83 inner,
84 base,
85 len,
86 pos: 0,
87 })
88 }
89
90 pub fn len(&self) -> u64 {
92 self.len
93 }
94
95 pub fn is_empty(&self) -> bool {
97 self.len == 0
98 }
99
100 pub fn base(&self) -> u64 {
102 self.base
103 }
104
105 pub fn into_inner(self) -> Box<dyn BytesSource> {
109 self.inner
110 }
111}
112
113pub fn stream_len(src: &mut dyn BytesSource) -> io::Result<u64> {
118 let saved = src.stream_position()?;
119 let end = src.seek(SeekFrom::End(0))?;
120 if saved != end {
123 src.seek(SeekFrom::Start(saved))?;
124 }
125 Ok(end)
126}
127
128impl Read for SubSource {
129 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
130 if buf.is_empty() || self.pos >= self.len {
131 return Ok(0);
132 }
133 let remaining = (self.len - self.pos) as usize;
135 let want = buf.len().min(remaining);
136
137 let inner_off = self.base + self.pos;
145 self.inner.seek(SeekFrom::Start(inner_off))?;
146 let n = self.inner.read(&mut buf[..want])?;
147 self.pos += n as u64;
148 Ok(n)
149 }
150}
151
152impl Seek for SubSource {
153 fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
154 let new_pos = match from {
155 SeekFrom::Start(n) => n,
156 SeekFrom::End(d) => add_signed(self.len, d)?,
157 SeekFrom::Current(d) => add_signed(self.pos, d)?,
158 };
159 self.pos = new_pos;
163 Ok(self.pos)
164 }
165}
166
167fn add_signed(base: u64, delta: i64) -> io::Result<u64> {
168 let result = if delta >= 0 {
169 base.checked_add(delta as u64)
170 } else {
171 base.checked_sub(delta.unsigned_abs())
172 };
173 result.ok_or_else(|| {
174 io::Error::new(
175 io::ErrorKind::InvalidInput,
176 "SubSource: seek resolves to a negative or overflowing position",
177 )
178 })
179}
180
181#[cfg(test)]
182mod tests {
183 use std::io::Cursor;
184
185 use super::*;
186
187 fn ramp(n: usize) -> Vec<u8> {
188 (0..n).map(|i| (i & 0xff) as u8).collect()
189 }
190
191 #[test]
192 fn window_reads_the_correct_slice() {
193 let data = ramp(256);
194 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data.clone()));
195 let mut sub = SubSource::new(inner, 50, 40).unwrap();
196 assert_eq!(sub.len(), 40);
197 assert_eq!(sub.base(), 50);
198 let mut out = vec![0u8; 40];
199 sub.read_exact(&mut out).unwrap();
200 assert_eq!(out, &data[50..90]);
201 }
202
203 #[test]
204 fn read_past_window_returns_eof() {
205 let data = ramp(128);
206 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
207 let mut sub = SubSource::new(inner, 10, 20).unwrap();
208 let mut out = vec![0u8; 50];
209 let n = sub.read(&mut out).unwrap();
210 assert_eq!(n, 20); let n2 = sub.read(&mut out).unwrap();
212 assert_eq!(n2, 0); }
214
215 #[test]
216 fn seek_within_window_then_read() {
217 let data = ramp(256);
218 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data.clone()));
219 let mut sub = SubSource::new(inner, 100, 100).unwrap();
220 sub.seek(SeekFrom::Start(50)).unwrap();
222 let mut byte = [0u8; 1];
223 sub.read_exact(&mut byte).unwrap();
224 assert_eq!(byte[0], data[150]);
225 }
226
227 #[test]
228 fn seek_end_anchors_at_window_end() {
229 let data = ramp(64);
230 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
231 let mut sub = SubSource::new(inner, 8, 16).unwrap();
232 let pos = sub.seek(SeekFrom::End(0)).unwrap();
233 assert_eq!(pos, 16);
234 let mut byte = [0u8; 1];
235 assert_eq!(sub.read(&mut byte).unwrap(), 0);
236 }
237
238 #[test]
239 fn seek_current_relative() {
240 let data = ramp(128);
241 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
242 let mut sub = SubSource::new(inner, 0, 64).unwrap();
243 sub.seek(SeekFrom::Start(20)).unwrap();
244 let p = sub.seek(SeekFrom::Current(5)).unwrap();
245 assert_eq!(p, 25);
246 let p = sub.seek(SeekFrom::Current(-10)).unwrap();
247 assert_eq!(p, 15);
248 }
249
250 #[test]
251 fn seek_before_zero_errors() {
252 let data = ramp(32);
253 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
254 let mut sub = SubSource::new(inner, 0, 16).unwrap();
255 let r = sub.seek(SeekFrom::Current(-1));
256 assert!(r.is_err());
257 let r = sub.seek(SeekFrom::End(-100));
258 assert!(r.is_err());
259 }
260
261 #[test]
262 fn seek_past_window_then_read_returns_zero() {
263 let data = ramp(64);
265 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
266 let mut sub = SubSource::new(inner, 0, 32).unwrap();
267 sub.seek(SeekFrom::Start(1000)).unwrap();
268 let mut out = [0u8; 8];
269 assert_eq!(sub.read(&mut out).unwrap(), 0);
270 sub.seek(SeekFrom::Start(4)).unwrap();
272 let mut byte = [0u8; 1];
273 sub.read_exact(&mut byte).unwrap();
274 assert_eq!(byte[0], 4);
275 }
276
277 #[test]
278 fn window_extending_past_inner_rejected() {
279 let data = ramp(64);
280 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
281 let r = SubSource::new(inner, 50, 50); assert!(r.is_err());
283 }
284
285 #[test]
286 fn window_at_exact_end_accepted() {
287 let data = ramp(64);
288 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
289 let mut sub = SubSource::new(inner, 30, 34).unwrap();
291 let mut out = Vec::new();
292 sub.read_to_end(&mut out).unwrap();
293 assert_eq!(out.len(), 34);
294 assert_eq!(out[0], 30);
295 assert_eq!(out[33], 63);
296 }
297
298 #[test]
299 fn zero_length_window() {
300 let data = ramp(64);
301 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
302 let mut sub = SubSource::new(inner, 16, 0).unwrap();
303 assert!(sub.is_empty());
304 let mut out = [0u8; 4];
305 assert_eq!(sub.read(&mut out).unwrap(), 0);
306 }
307
308 #[test]
309 fn overflowing_window_rejected() {
310 let data = ramp(64);
311 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data));
312 let r = SubSource::new(inner, u64::MAX, 1);
313 assert!(r.is_err());
314 }
315
316 #[test]
317 fn into_inner_returns_inner_source() {
318 let data = ramp(64);
319 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data.clone()));
320 let mut sub = SubSource::new(inner, 8, 16).unwrap();
321 let mut byte = [0u8; 1];
322 sub.read_exact(&mut byte).unwrap();
323 let mut recovered = sub.into_inner();
324 recovered.seek(SeekFrom::Start(0)).unwrap();
326 let mut head = [0u8; 4];
327 recovered.read_exact(&mut head).unwrap();
328 assert_eq!(head, [0, 1, 2, 3]);
329 }
330
331 #[test]
332 fn nested_windows_compose() {
333 let data = ramp(256);
334 let inner: Box<dyn BytesSource> = Box::new(Cursor::new(data.clone()));
335 let outer = SubSource::new(inner, 64, 128).unwrap();
336 let mut nested = SubSource::new(Box::new(outer), 16, 32).unwrap();
338 let mut out = vec![0u8; 32];
339 nested.read_exact(&mut out).unwrap();
340 assert_eq!(out, &data[80..112]);
341 }
342
343 #[test]
344 fn stream_len_helper_preserves_position() {
345 let data = ramp(128);
346 let mut src: Box<dyn BytesSource> = Box::new(Cursor::new(data));
347 src.seek(SeekFrom::Start(42)).unwrap();
348 let len = stream_len(&mut *src).unwrap();
349 assert_eq!(len, 128);
350 assert_eq!(src.stream_position().unwrap(), 42);
351 }
352}