Skip to main content

rar_stream/
file_media.rs

1//! FileMedia trait - abstract byte source for RAR reading.
2
3use crate::error::Result;
4use std::io::{Read, Seek, SeekFrom};
5
6/// Interval for reading a byte range.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub struct ReadInterval {
9    pub start: u64,
10    pub end: u64,
11}
12
13/// Local file implementation.
14#[derive(Debug, Clone)]
15pub struct LocalFileMedia {
16    path: String,
17    name: String,
18    length: u64,
19}
20
21impl LocalFileMedia {
22    pub fn new(path: &str) -> std::io::Result<Self> {
23        let metadata = std::fs::metadata(path)?;
24        let name = std::path::Path::new(path)
25            .file_name()
26            .and_then(|n| n.to_str())
27            .unwrap_or("unknown")
28            .to_string();
29
30        Ok(Self {
31            path: path.to_string(),
32            name,
33            length: metadata.len(),
34        })
35    }
36
37    pub fn length(&self) -> u64 {
38        self.length
39    }
40
41    pub fn name(&self) -> &str {
42        &self.name
43    }
44
45    /// Sync read
46    pub fn read_range_sync(&self, interval: ReadInterval) -> Result<Vec<u8>> {
47        let mut file = std::fs::File::open(&self.path)?;
48        file.seek(SeekFrom::Start(interval.start))?;
49        let len = (interval.end - interval.start + 1) as usize;
50        let mut buffer = vec![0u8; len];
51        file.read_exact(&mut buffer)?;
52        Ok(buffer)
53    }
54}
55
56// Async FileMedia trait (requires 'async' feature)
57#[cfg(feature = "async")]
58use std::future::Future;
59#[cfg(feature = "async")]
60use std::pin::Pin;
61
62/// Abstract file source that can provide byte ranges asynchronously.
63#[cfg(feature = "async")]
64pub trait FileMedia: Send + Sync {
65    fn length(&self) -> u64;
66    fn name(&self) -> &str;
67    fn read_range(
68        &self,
69        interval: ReadInterval,
70    ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>> + Send + '_>>;
71}
72
73#[cfg(feature = "async")]
74impl FileMedia for LocalFileMedia {
75    fn length(&self) -> u64 {
76        self.length
77    }
78
79    fn name(&self) -> &str {
80        &self.name
81    }
82
83    fn read_range(
84        &self,
85        interval: ReadInterval,
86    ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>> + Send + '_>> {
87        let path = self.path.clone();
88        Box::pin(async move {
89            use tokio::io::{AsyncReadExt, AsyncSeekExt};
90            let mut file = tokio::fs::File::open(&path).await?;
91            file.seek(std::io::SeekFrom::Start(interval.start)).await?;
92            let len = (interval.end - interval.start + 1) as usize;
93            let mut buffer = vec![0u8; len];
94            file.read_exact(&mut buffer).await?;
95            Ok(buffer)
96        })
97    }
98}