Skip to main content

copc_streaming/
byte_source.rs

1use std::future::Future;
2
3use crate::error::CopcError;
4
5/// Async random-access byte source.
6///
7/// Implementations can back this with HTTP range requests, local file I/O,
8/// in-memory buffers, or any other random-access mechanism.
9///
10/// All methods return non-Send futures for WASM compatibility.
11pub trait ByteSource {
12    /// Read `length` bytes starting at `offset`.
13    fn read_range(
14        &self,
15        offset: u64,
16        length: u64,
17    ) -> impl Future<Output = Result<Vec<u8>, CopcError>>;
18
19    /// Total size of the source in bytes, if known.
20    fn size(&self) -> impl Future<Output = Result<Option<u64>, CopcError>>;
21
22    /// Read multiple ranges in one logical operation.
23    ///
24    /// The default implementation issues sequential reads.
25    /// HTTP implementations should override to issue parallel requests.
26    fn read_ranges(
27        &self,
28        ranges: &[(u64, u64)],
29    ) -> impl Future<Output = Result<Vec<Vec<u8>>, CopcError>> {
30        async move {
31            let mut results = Vec::with_capacity(ranges.len());
32            for &(offset, length) in ranges {
33                results.push(self.read_range(offset, length).await?);
34            }
35            Ok(results)
36        }
37    }
38}
39
40/// In-memory byte source, useful for testing and when data is already loaded.
41impl ByteSource for Vec<u8> {
42    async fn read_range(&self, offset: u64, length: u64) -> Result<Vec<u8>, CopcError> {
43        let start = offset as usize;
44        let end = start + length as usize;
45        if end > self.len() {
46            return Err(CopcError::Io(std::io::Error::new(
47                std::io::ErrorKind::UnexpectedEof,
48                format!(
49                    "read_range({offset}, {length}) out of bounds (size {})",
50                    self.len()
51                ),
52            )));
53        }
54        Ok(self[start..end].to_vec())
55    }
56
57    async fn size(&self) -> Result<Option<u64>, CopcError> {
58        Ok(Some(self.len() as u64))
59    }
60}
61
62/// Byte source over a shared slice reference.
63impl ByteSource for &[u8] {
64    async fn read_range(&self, offset: u64, length: u64) -> Result<Vec<u8>, CopcError> {
65        let start = offset as usize;
66        let end = start + length as usize;
67        if end > self.len() {
68            return Err(CopcError::Io(std::io::Error::new(
69                std::io::ErrorKind::UnexpectedEof,
70                format!(
71                    "read_range({offset}, {length}) out of bounds (size {})",
72                    self.len()
73                ),
74            )));
75        }
76        Ok(self[start..end].to_vec())
77    }
78
79    async fn size(&self) -> Result<Option<u64>, CopcError> {
80        Ok(Some(self.len() as u64))
81    }
82}