pgs_parse/
pgs_file.rs

1use std::{fs::{File, Metadata}, io::{Read, Seek}};
2
3use crate::pgs_error::{Result, Error};
4
5/// A wrapper around a `File` that includes file metadata and provides methods to read data.
6///
7/// This struct provides methods to read bytes from a file and check if the end of the file has been reached.
8/// It also maintains file metadata for boundary checking.
9#[derive(Debug)]
10pub struct PgsFile {
11    file: File,
12    metadata: Metadata
13}
14
15impl PgsFile {
16    /// Creates a new `PgsFile` instance.
17    ///
18    /// # Arguments
19    /// * `file` - The `File` instance to be wrapped by `PgsFile`.
20    ///
21    /// # Returns
22    /// Returns a `Result` containing either a `PgsFile` instance or an `Error` if file metadata retrieval fails.
23    pub(crate) fn new(file: File) -> Result<Self> {
24        Ok(PgsFile {
25            metadata: file.metadata()?,
26            file
27        })
28    }
29
30    /// Returns a reference to the file metadata.
31    ///
32    /// # Returns
33    /// Returns a reference to the `Metadata` associated with the file.    
34    pub fn metadata(&self) -> &Metadata {
35        &self.metadata
36    }
37
38    /// Reads bytes from the file into the provided buffer.
39    ///
40    /// # Arguments
41    /// * `buffer` - A mutable byte slice where the data will be read into.
42    ///
43    /// # Returns
44    /// Returns a `Result` indicating success or an `Error` if reading the bytes fails or if the read operation would
45    /// exceed the file's length.    
46    pub fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<()> {
47        if self.file.stream_position()? + buffer.len() as u64 > self.metadata.len() {
48            return Err(Error::File(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "end of file")));
49        }
50        self.file.read_exact(buffer)?;
51        Ok(())
52    }
53
54    /// Reads a fixed number of bytes from the file into a fixed-size array.
55    ///
56    /// # Type Parameters
57    /// * `N` - The number of bytes to read, defined as a constant generic parameter.
58    ///
59    /// # Returns
60    /// Returns a `Result` containing either a fixed-size array of bytes or an `Error` if reading the bytes fails or if
61    /// the read operation would exceed the file's length.
62    pub fn read_n_bytes<const N: usize>(&mut self) -> Result<[u8; N]> {
63        if self.file.stream_position()? + N as u64 > self.metadata.len() {
64            return Err(Error::File(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "end of file")));
65        }
66        let mut buffer: [u8; N] = [0; N];
67        self.file.read_exact(&mut buffer)?;
68        Ok(buffer)
69    }
70
71    /// Checks if the current position in the file is at or past the end of the file.
72    ///
73    /// # Returns
74    ///
75    /// Returns a `Result` containing a boolean value. `true` indicates that the end of the file has been reached or
76    /// exceeded, while `false` indicates that there is more data to read.
77    pub fn is_eof(&mut self) -> Result<bool> {
78        Ok(self.file.stream_position()? >= self.metadata.len())
79    }
80}