keramics_vfs/
file_resolver.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 keramics_core::{DataStreamReference, ErrorTrace};
15use keramics_formats::{FileResolver, FileResolverReference, PathComponent};
16
17use crate::file_entry::VfsFileEntry;
18use crate::path::VfsPath;
19use crate::types::VfsFileSystemReference;
20
21pub struct VfsFileResolver {
22    /// File system.
23    file_system: VfsFileSystemReference,
24
25    /// Base path.
26    base_path: VfsPath,
27}
28
29impl VfsFileResolver {
30    /// Creates a new file resolver.
31    pub fn new(file_system: &VfsFileSystemReference, base_path: VfsPath) -> Self {
32        Self {
33            file_system: file_system.clone(),
34            base_path: base_path,
35        }
36    }
37}
38
39impl FileResolver for VfsFileResolver {
40    /// Retrieves a data stream with the specified path.
41    fn get_data_stream(
42        &self,
43        path_components: &[PathComponent],
44    ) -> Result<Option<DataStreamReference>, ErrorTrace> {
45        let vfs_path: VfsPath = match self.base_path.new_with_join(path_components) {
46            Ok(path) => path,
47            Err(mut error) => {
48                keramics_core::error_trace_add_frame!(error, "Unable to create VFS path");
49                return Err(error);
50            }
51        };
52        let result: Option<VfsFileEntry> = match self.file_system.get_file_entry_by_path(&vfs_path)
53        {
54            Ok(result) => result,
55            Err(mut error) => {
56                keramics_core::error_trace_add_frame!(error, "Unable to retrieve file entry");
57                return Err(error);
58            }
59        };
60        match result {
61            // TODO: replace by get_data_fork_by_name
62            Some(file_entry) => file_entry.get_data_stream_by_name(None),
63            None => Ok(None),
64        }
65    }
66}
67
68/// Creates a new  Virtual File System (VFS) file resolver.
69pub fn new_vfs_file_resolver(
70    file_system: &VfsFileSystemReference,
71    base_path: VfsPath,
72) -> Result<FileResolverReference, ErrorTrace> {
73    let file_resolver: VfsFileResolver = VfsFileResolver::new(file_system, base_path);
74    Ok(FileResolverReference::new(Box::new(file_resolver)))
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    use crate::enums::VfsType;
82    use crate::file_system::VfsFileSystem;
83
84    #[test]
85    fn test_get_data_stream() -> Result<(), ErrorTrace> {
86        let file_system: VfsFileSystemReference =
87            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
88        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Os, "../test_data");
89        let file_resolver: FileResolverReference = new_vfs_file_resolver(&file_system, vfs_path)?;
90
91        let path_components: [PathComponent; 1] = [PathComponent::from("file.txt")];
92        let result: Option<DataStreamReference> =
93            file_resolver.get_data_stream(&path_components)?;
94        assert!(result.is_some());
95
96        Ok(())
97    }
98
99    #[test]
100    fn test_new_vfs_file_resolver() -> Result<(), ErrorTrace> {
101        let file_system: VfsFileSystemReference =
102            VfsFileSystemReference::new(VfsFileSystem::new(&VfsType::Os));
103        let vfs_path: VfsPath = VfsPath::from_path(&VfsType::Os, "../test_data");
104        let _ = new_vfs_file_resolver(&file_system, vfs_path)?;
105
106        Ok(())
107    }
108}