Skip to main content

qubit_fs/provider/
file_resource.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Bound filesystem resource.
11
12use std::sync::Arc;
13
14use crate::{
15    CopyOptions,
16    CopyOutcome,
17    CreateDirOptions,
18    DeleteOptions,
19    DirectoryStream,
20    FileMetadata,
21    FileReader,
22    FileSystem,
23    FileSystemExt,
24    FileWriter,
25    FsPath,
26    FsResult,
27    ListOptions,
28    ReadOptions,
29    RenameOptions,
30    WriteOptions,
31    WriteOutcome,
32};
33
34/// A filesystem path bound to the filesystem that owns it.
35///
36/// `FileResource` is the high-level resource object returned by
37/// [`FileSystems::resource`](crate::FileSystems::resource) and
38/// [`FileSystemRegistry::resource`](crate::FileSystemRegistry::resource). It
39/// keeps path operations close to the resolved filesystem without making
40/// [`FsPath`](crate::FsPath) itself carry any backend state.
41#[derive(Debug, Clone)]
42pub struct FileResource {
43    fs: Arc<dyn FileSystem>,
44    path: FsPath,
45}
46
47impl FileResource {
48    /// Creates a new filesystem resource.
49    ///
50    /// # Parameters
51    /// - `fs`: Filesystem instance that owns the path.
52    /// - `path`: Filesystem-local path.
53    ///
54    /// # Returns
55    /// A resource bound to the supplied filesystem and path.
56    #[must_use]
57    pub fn new(fs: Arc<dyn FileSystem>, path: FsPath) -> Self {
58        Self { fs, path }
59    }
60
61    /// Returns the filesystem that owns this resource.
62    ///
63    /// # Returns
64    /// A shared reference to the owning filesystem.
65    #[must_use]
66    pub fn fs(&self) -> &dyn FileSystem {
67        self.fs.as_ref()
68    }
69
70    /// Returns the filesystem-local path of this resource.
71    ///
72    /// # Returns
73    /// A shared reference to the filesystem-local path.
74    #[must_use]
75    pub fn path(&self) -> &FsPath {
76        &self.path
77    }
78
79    /// Reads metadata for this resource.
80    ///
81    /// # Returns
82    /// File metadata for this resource.
83    ///
84    /// # Errors
85    /// Returns an error when the owning filesystem cannot read metadata for the
86    /// resource path.
87    pub fn metadata(&self) -> FsResult<FileMetadata> {
88        self.fs.path_metadata(&self.path)
89    }
90
91    /// Checks whether this resource exists.
92    ///
93    /// # Returns
94    /// `true` when the resource exists.
95    ///
96    /// # Errors
97    /// Returns an error when the owning filesystem cannot determine existence
98    /// for the resource path.
99    pub fn exists(&self) -> FsResult<bool> {
100        self.fs.exists(&self.path)
101    }
102
103    /// Lists child entries under this resource.
104    ///
105    /// # Parameters
106    /// - `options`: Listing options.
107    ///
108    /// # Returns
109    /// A directory stream for the resource path.
110    ///
111    /// # Errors
112    /// Returns an error when the owning filesystem cannot open a directory
113    /// stream for the resource path.
114    pub fn list(&self, options: &ListOptions) -> FsResult<Box<dyn DirectoryStream>> {
115        self.fs.list(&self.path, options)
116    }
117
118    /// Opens this resource for reading.
119    ///
120    /// # Parameters
121    /// - `options`: Read options.
122    ///
123    /// # Returns
124    /// A file reader for the resource path.
125    ///
126    /// # Errors
127    /// Returns an error when the owning filesystem cannot open the resource for
128    /// reading.
129    pub fn open_reader(&self, options: &ReadOptions) -> FsResult<Box<dyn FileReader>> {
130        self.fs.open_reader(&self.path, options)
131    }
132
133    /// Opens this resource for writing.
134    ///
135    /// # Parameters
136    /// - `options`: Write options.
137    ///
138    /// # Returns
139    /// A file writer for the resource path.
140    ///
141    /// # Errors
142    /// Returns an error when the owning filesystem cannot open the resource for
143    /// writing.
144    pub fn open_writer(&self, options: &WriteOptions) -> FsResult<Box<dyn FileWriter>> {
145        self.fs.open_writer(&self.path, options)
146    }
147
148    /// Reads this resource into memory.
149    ///
150    /// # Returns
151    /// The complete byte content of this resource.
152    ///
153    /// # Errors
154    /// Returns an error when the owning filesystem cannot open or read the
155    /// resource.
156    pub fn read_all(&self) -> FsResult<Vec<u8>> {
157        self.fs.read_all(&self.path)
158    }
159
160    /// Writes all bytes to this resource.
161    ///
162    /// # Parameters
163    /// - `bytes`: Complete byte content to write.
164    ///
165    /// # Returns
166    /// Write outcome reported by the owning filesystem.
167    ///
168    /// # Errors
169    /// Returns an error when the owning filesystem cannot open, write, flush, or
170    /// commit the resource.
171    pub fn write_all(&self, bytes: &[u8]) -> FsResult<WriteOutcome> {
172        self.fs.write_all(&self.path, bytes)
173    }
174
175    /// Creates this resource as a directory.
176    ///
177    /// # Parameters
178    /// - `options`: Directory creation options.
179    ///
180    /// # Errors
181    /// Returns an error when the owning filesystem cannot create the directory.
182    pub fn create_dir(&self, options: &CreateDirOptions) -> FsResult<()> {
183        self.fs.create_dir(&self.path, options)
184    }
185
186    /// Deletes this resource.
187    ///
188    /// # Parameters
189    /// - `options`: Delete options.
190    ///
191    /// # Errors
192    /// Returns an error when the owning filesystem cannot delete the resource.
193    pub fn delete(&self, options: &DeleteOptions) -> FsResult<()> {
194        self.fs.delete(&self.path, options)
195    }
196
197    /// Renames this resource to another filesystem-local path.
198    ///
199    /// # Parameters
200    /// - `target`: Target filesystem-local path.
201    /// - `options`: Rename options.
202    ///
203    /// # Errors
204    /// Returns an error when the owning filesystem cannot rename the resource.
205    pub fn rename_to(&self, target: &FsPath, options: &RenameOptions) -> FsResult<()> {
206        self.fs.rename(&self.path, target, options)
207    }
208
209    /// Copies this resource to another filesystem-local path.
210    ///
211    /// # Parameters
212    /// - `target`: Target filesystem-local path.
213    /// - `options`: Copy options.
214    ///
215    /// # Returns
216    /// Copy outcome reported by the owning filesystem.
217    ///
218    /// # Errors
219    /// Returns an error when the owning filesystem cannot copy the resource.
220    pub fn copy_to(&self, target: &FsPath, options: &CopyOptions) -> FsResult<CopyOutcome> {
221        self.fs.copy(&self.path, target, options)
222    }
223}