coven_database/
input_bytes.rs1use super::{read_local, sql_offset, InputConnection, InputRead, RANGES};
4use std::io::{self, Read, Seek, SeekFrom};
5use std::sync::Arc;
6
7#[derive(Clone)]
10pub struct RetainedBytes {
11 reader: InputConnection,
12 reading: Arc<InputRead>,
13 position: u64,
14 length: u64,
15}
16
17impl RetainedBytes {
18 pub(super) fn new(reader: InputConnection, reading: Arc<InputRead>, length: u64) -> Self {
19 Self { reader, reading, position: 0, length }
20 }
21
22 pub fn len(&self) -> u64 {
24 self.length
25 }
26
27 pub fn is_empty(&self) -> bool {
29 self.length == 0
30 }
31}
32
33impl Read for RetainedBytes {
34 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
35 let length = self
36 .length
37 .saturating_sub(self.position)
38 .min(output.len() as u64)
39 .min(coven_format::chunks::CHUNK_SIZE as u64);
40 if length == 0 {
41 return Ok(0);
42 }
43 let start = self.position;
44 let end = start + length;
45 let ranges = read_local(&self.reader, |db| {
46 db.query(RANGES, (self.reading.id, sql_offset(start)?, sql_offset(end)?), |row| {
47 Ok((row.get::<_, i64>(0)? as u64, row.get::<_, Vec<u8>>(1)?))
48 })
49 })
50 .map_err(io::Error::other)?;
51 let mut copied = 0;
52 for (offset, bytes) in ranges {
53 if offset != start + copied as u64 {
54 break;
55 }
56 output[copied..copied + bytes.len()].copy_from_slice(&bytes);
57 copied += bytes.len();
58 }
59 if copied == 0 {
60 return Err(io::Error::new(
61 io::ErrorKind::UnexpectedEof,
62 "provider bytes have not been received",
63 ));
64 }
65 #[cfg(any(test, feature = "test-utils"))]
66 coven_foundation::test_work::retained_read(copied);
67 self.position += copied as u64;
68 Ok(copied)
69 }
70}
71
72impl Seek for RetainedBytes {
73 fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
74 let position = match from {
75 SeekFrom::Start(position) => Some(position),
76 SeekFrom::End(offset) => self.length.checked_add_signed(offset),
77 SeekFrom::Current(offset) => self.position.checked_add_signed(offset),
78 }
79 .ok_or_else(|| {
80 io::Error::new(io::ErrorKind::InvalidInput, "input position is outside u64")
81 })?;
82 self.position = position;
83 Ok(position)
84 }
85 fn stream_position(&mut self) -> io::Result<u64> {
86 Ok(self.position)
87 }
88}