Skip to main content

rar_stream/
rar_file_chunk.rs

1//! RarFileChunk - a byte range within a single RAR volume.
2
3use crate::error::Result;
4use crate::file_media::{FileMedia, ReadInterval};
5use std::fmt;
6use std::sync::Arc;
7
8/// A byte range within a single FileMedia (RAR volume).
9#[derive(Clone)]
10pub struct RarFileChunk {
11    file_media: Arc<dyn FileMedia>,
12    pub start_offset: u64,
13    pub end_offset: u64,
14}
15
16impl fmt::Debug for RarFileChunk {
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        f.debug_struct("RarFileChunk")
19            .field("file_name", &self.file_media.name())
20            .field("start_offset", &self.start_offset)
21            .field("end_offset", &self.end_offset)
22            .finish()
23    }
24}
25
26impl RarFileChunk {
27    pub fn new(file_media: Arc<dyn FileMedia>, start_offset: u64, end_offset: u64) -> Self {
28        Self {
29            file_media,
30            start_offset,
31            end_offset,
32        }
33    }
34
35    /// Length of this chunk in bytes.
36    pub fn length(&self) -> u64 {
37        if self.end_offset >= self.start_offset {
38            self.end_offset - self.start_offset + 1
39        } else {
40            0
41        }
42    }
43
44    /// Create a new chunk with the start offset moved forward.
45    pub fn pad_start(&self, padding: u64) -> Self {
46        Self {
47            file_media: self.file_media.clone(),
48            start_offset: self.start_offset.saturating_add(padding),
49            end_offset: self.end_offset,
50        }
51    }
52
53    /// Create a new chunk with the end offset moved backward.
54    pub fn pad_end(&self, padding: u64) -> Self {
55        Self {
56            file_media: self.file_media.clone(),
57            start_offset: self.start_offset,
58            end_offset: self.end_offset.saturating_sub(padding),
59        }
60    }
61
62    /// Read the entire chunk.
63    pub async fn read(&self) -> Result<Vec<u8>> {
64        self.file_media
65            .read_range(ReadInterval {
66                start: self.start_offset,
67                end: self.end_offset,
68            })
69            .await
70    }
71
72    /// Read a portion of the chunk.
73    pub async fn read_range(&self, start: u64, end: u64) -> Result<Vec<u8>> {
74        self.file_media
75            .read_range(ReadInterval {
76                start: self.start_offset.saturating_add(start),
77                end: self.start_offset.saturating_add(end),
78            })
79            .await
80    }
81
82    /// Get the name of the file media (volume) this chunk belongs to.
83    pub fn volume_name(&self) -> &str {
84        self.file_media.name()
85    }
86}