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