blake_streams_core/
read.rs1use crate::{Head, StreamId};
2use anyhow::Result;
3use std::convert::TryInto;
4use std::fs::File;
5use std::io::{self, Read, Seek, SeekFrom};
6use std::path::Path;
7
8pub struct StreamReader {
9 file: File,
10 id: StreamId,
11 start: u64,
12 len: u64,
13 pos: u64,
14}
15
16impl StreamReader {
17 pub(crate) fn new(path: &Path, head: &Head, start: u64, len: u64) -> Result<Self> {
18 if start + len > head.len {
19 return Err(anyhow::anyhow!(
20 "trying to read after the end of the stream"
21 ));
22 }
23 let mut file = File::open(path)?;
24 file.seek(SeekFrom::Start(start))?;
25 Ok(Self {
26 file,
27 id: head.id,
28 start,
29 len,
30 pos: 0,
31 })
32 }
33
34 pub fn id(&self) -> &StreamId {
35 &self.id
36 }
37}
38
39impl Read for StreamReader {
40 fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
41 if self.pos >= self.len {
43 return Ok(0);
44 }
45 if buf.len() as u64 >= self.len - self.pos {
46 let (vbuf, _) = buf.split_at_mut((self.len - self.pos).try_into().unwrap());
47 buf = vbuf;
48 }
49 let n = self.file.read(buf)?;
50 self.pos += n as u64;
51 Ok(n)
52 }
53}
54
55impl Seek for StreamReader {
56 fn seek(&mut self, seek: SeekFrom) -> io::Result<u64> {
57 fn add_offset(position: i128, offset: i128) -> io::Result<u64> {
58 let sum = position + offset;
59 if sum < 0 {
60 Err(io::Error::new(
61 io::ErrorKind::InvalidInput,
62 "seek before beginning",
63 ))
64 } else if sum > u64::max_value() as i128 {
65 Err(io::Error::new(
66 io::ErrorKind::InvalidInput,
67 "seek target overflowed u64",
68 ))
69 } else {
70 Ok(sum as u64)
71 }
72 }
73 let pos = match seek {
75 SeekFrom::Start(start) => start,
76 SeekFrom::Current(current) => add_offset(self.pos as _, current as _)?,
77 SeekFrom::End(end) => add_offset(self.len as _, end as _)?,
78 };
79 let start = add_offset(self.start as _, pos as _)?;
80 self.file.seek(SeekFrom::Start(start))?;
81 self.pos = pos;
82 Ok(self.pos)
83 }
84
85 fn stream_position(&mut self) -> io::Result<u64> {
86 Ok(self.pos)
87 }
88}