keramics_core/
os_data_stream.rs

1/* Copyright 2024-2025 Joachim Metz <joachim.metz@gmail.com>
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may
5 * obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 * License for the specific language governing permissions and limitations
11 * under the License.
12 */
13
14use std::fs::{File, Metadata};
15use std::io::{Read, Seek, SeekFrom};
16use std::path::PathBuf;
17use std::sync::{Arc, RwLock};
18
19use super::data_stream::{DataStream, DataStreamReference};
20use super::errors::ErrorTrace;
21
22impl DataStream for File {
23    /// Retrieves the size of the data.
24    fn get_size(&mut self) -> Result<u64, ErrorTrace> {
25        let metadata: Metadata = match self.metadata() {
26            Ok(metadata) => metadata,
27            Err(error) => {
28                return Err(ErrorTrace::new(format!(
29                    "{}: Unable to retrieve file metadata with error: {}",
30                    crate::error_trace_function!(),
31                    error.to_string(),
32                )));
33            }
34        };
35        Ok(metadata.len())
36    }
37
38    /// Reads data at the current position.
39    fn read(&mut self, buf: &mut [u8]) -> Result<usize, ErrorTrace> {
40        match Read::read(self, buf) {
41            Ok(read_count) => Ok(read_count),
42            Err(error) => Err(ErrorTrace::new(format!(
43                "{}: Unable to read data with error: {}",
44                crate::error_trace_function!(),
45                error.to_string(),
46            ))),
47        }
48    }
49
50    /// Sets the current position of the data.
51    fn seek(&mut self, pos: SeekFrom) -> Result<u64, ErrorTrace> {
52        match Seek::seek(self, pos) {
53            Ok(offset) => Ok(offset),
54            Err(error) => Err(ErrorTrace::new(format!(
55                "{}: Unable to seek position with error: {}",
56                crate::error_trace_function!(),
57                error.to_string(),
58            ))),
59        }
60    }
61}
62
63/// Opens a file.
64macro_rules! open_file {
65    ( $path:expr ) => {
66        match File::open($path) {
67            Ok(file) => file,
68            Err(error) => {
69                return Err(ErrorTrace::new(format!(
70                    "{}: Unable to open file with error: {}",
71                    crate::error_trace_function!(),
72                    error.to_string(),
73                )));
74            }
75        }
76    };
77}
78
79/// Opens a new operating system data stream.
80pub fn open_os_data_stream(path: &PathBuf) -> Result<DataStreamReference, ErrorTrace> {
81    let file: File = open_file!(path);
82
83    Ok(Arc::new(RwLock::new(file)))
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_get_size() -> Result<(), ErrorTrace> {
92        let mut file: File = open_file!("../test_data/file.txt");
93
94        let size: u64 = file.get_size()?;
95        assert_eq!(size, 202);
96
97        Ok(())
98    }
99
100    #[test]
101    fn test_open_os_data_stream() -> Result<(), ErrorTrace> {
102        let path_buf: PathBuf = PathBuf::from("../test_data/file.txt");
103        let _ = open_os_data_stream(&path_buf)?;
104
105        Ok(())
106    }
107}