qubit_fs/spi/file_system_spi.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Synchronous provider implementation contract.
9
10use super::CopyAttempt;
11use super::CopyDeclineReason;
12use super::CopyRequest;
13use super::CreateDirectoryRequest;
14use super::CreateTempDirectoryRequest;
15use super::CreateTempFileRequest;
16use super::DeleteDirectoryRequest;
17use super::DeleteFileRequest;
18use super::ListRequest;
19use super::OpenReaderRequest;
20use super::OpenWriterRequest;
21use super::OpenedDirectoryStream;
22use super::OpenedReader;
23use super::OpenedTempDirectory;
24use super::OpenedTempFile;
25use super::OpenedWriter;
26use super::ProviderProperties;
27use super::RenameRequest;
28use super::SpiCopyFailure;
29use super::SpiRenameFailure;
30use super::StatRequest;
31use super::StatResponse;
32use crate::directory::CreateDirectoryOutcome;
33use crate::directory::DeleteOutcome;
34use crate::error::FsEffectState;
35use crate::error::FsError;
36use crate::error::FsErrorKind;
37use crate::error::FsOperation;
38use crate::error::FsResult;
39use crate::rename::RenameFailureState;
40use crate::rename::RenameOutcome;
41
42/// Synchronous provider implementation contract.
43///
44/// # Examples
45///
46/// ```
47/// use qubit_fs::spi::FileSystemSpi;
48///
49/// fn accepts_provider<T: FileSystemSpi>() {}
50/// ```
51pub trait FileSystemSpi: Send + Sync {
52 /// Returns one immutable property snapshot.
53 ///
54 /// # Returns
55 /// The provider's immutable property snapshot.
56 fn properties(&self) -> ProviderProperties;
57 /// Reads metadata for a validated request.
58 ///
59 /// # Parameters
60 /// - `request`: Facade-validated stat request.
61 ///
62 /// # Returns
63 /// Path-bound provider metadata.
64 ///
65 /// # Errors
66 /// Returns the provider lookup failure with filesystem context.
67 fn stat(&self, request: StatRequest<'_>) -> FsResult<StatResponse>;
68 /// Opens a directory stream.
69 ///
70 /// # Parameters
71 /// - `request`: Facade-validated list request.
72 ///
73 /// # Returns
74 /// An opened provider enumeration session.
75 ///
76 /// # Errors
77 /// Returns the provider open failure with filesystem context.
78 fn list(&self, request: ListRequest<'_>) -> FsResult<OpenedDirectoryStream> {
79 Err(match request.scope().path() {
80 Some(path) => unsupported(FsOperation::List, path),
81 None => FsError::new(
82 FsErrorKind::UnsupportedOperation,
83 FsOperation::List,
84 "provider operation is not supported",
85 ),
86 })
87 }
88 /// Opens a reader.
89 ///
90 /// # Parameters
91 /// - `request`: Facade-validated reader request.
92 ///
93 /// # Returns
94 /// An identity-bound provider reader.
95 ///
96 /// # Errors
97 /// Returns the provider open failure with filesystem context.
98 fn open_reader(&self, request: OpenReaderRequest<'_>) -> FsResult<OpenedReader> {
99 Err(unsupported(FsOperation::OpenReader, request.path()))
100 }
101 /// Opens a writer.
102 ///
103 /// An unsuccessful open must describe its external effects. Attach
104 /// `FsEffectState::Unchanged` only when no mutation occurred and no cleanup
105 /// responsibility remains. Missing evidence is conservatively indeterminate
106 /// in aggregate operations, including an `AlreadyExists` skip request.
107 ///
108 /// # Parameters
109 /// - `request`: Facade-validated writer request.
110 ///
111 /// # Returns
112 /// An identity-bound provider writer.
113 ///
114 /// # Errors
115 /// Returns the provider open failure with filesystem context.
116 fn open_writer(&self, request: OpenWriterRequest<'_>) -> FsResult<OpenedWriter> {
117 Err(unsupported(FsOperation::OpenWriter, request.path()).with_effect_state(FsEffectState::Unchanged))
118 }
119 /// Creates a directory.
120 ///
121 /// # Parameters
122 /// - `request`: Facade-validated directory-creation request.
123 ///
124 /// # Returns
125 /// The confirmed creation outcome.
126 ///
127 /// # Errors
128 /// Returns the provider creation failure with filesystem context.
129 fn create_directory(&self, request: CreateDirectoryRequest<'_>) -> FsResult<CreateDirectoryOutcome> {
130 Err(unsupported(FsOperation::CreateDir, request.path()))
131 }
132 /// Deletes a file.
133 ///
134 /// # Parameters
135 /// - `request`: Facade-validated file-deletion request.
136 ///
137 /// # Returns
138 /// The confirmed deletion outcome.
139 ///
140 /// # Errors
141 /// Returns the provider deletion failure with filesystem context.
142 fn delete_file(&self, request: DeleteFileRequest<'_>) -> FsResult<DeleteOutcome> {
143 Err(unsupported(FsOperation::Delete, request.path()))
144 }
145 /// Deletes a directory.
146 ///
147 /// # Parameters
148 /// - `request`: Facade-validated directory-deletion request.
149 ///
150 /// # Returns
151 /// The confirmed deletion outcome.
152 ///
153 /// # Errors
154 /// Returns the provider deletion failure with filesystem context.
155 fn delete_directory(&self, request: DeleteDirectoryRequest<'_>) -> FsResult<DeleteOutcome> {
156 Err(unsupported(FsOperation::Delete, request.path()))
157 }
158 /// Attempts an optional provider copy primitive.
159 ///
160 /// # Parameters
161 /// - `_request`: Facade-validated copy request.
162 ///
163 /// # Returns
164 /// A completed outcome or a typed decline reason.
165 ///
166 /// # Errors
167 /// Returns a typed failure preserving confirmed publication progress.
168 #[inline]
169 fn try_copy(&self, _request: CopyRequest<'_>) -> Result<CopyAttempt, SpiCopyFailure> {
170 Ok(CopyAttempt::Declined(CopyDeclineReason::NotImplemented))
171 }
172 /// Renames a resource.
173 ///
174 /// # Parameters
175 /// - `request`: Facade-validated rename request.
176 ///
177 /// # Returns
178 /// The confirmed rename outcome.
179 ///
180 /// # Errors
181 /// Returns a typed failure preserving confirmed rename progress.
182 fn rename(&self, request: RenameRequest<'_>) -> Result<RenameOutcome, SpiRenameFailure> {
183 Err(SpiRenameFailure::new(
184 unsupported(FsOperation::Rename, request.source()).with_target(request.target().clone()),
185 RenameFailureState::Unchanged,
186 ))
187 }
188 /// Creates a temporary file.
189 ///
190 /// # Parameters
191 /// - `request`: Validated temporary-file creation request.
192 ///
193 /// # Returns
194 /// An identity-bound temporary-file session.
195 ///
196 /// # Errors
197 /// Returns the provider creation failure with filesystem context.
198 fn create_temp_file(&self, _request: CreateTempFileRequest) -> FsResult<OpenedTempFile> {
199 Err(FsError::new(
200 FsErrorKind::UnsupportedOperation,
201 FsOperation::CreateTemp,
202 "provider does not implement this operation",
203 ))
204 }
205 /// Creates a temporary directory.
206 ///
207 /// # Parameters
208 /// - `request`: Validated temporary-directory creation request.
209 ///
210 /// # Returns
211 /// An identity-bound temporary-directory session.
212 ///
213 /// # Errors
214 /// Returns the provider creation failure with filesystem context.
215 fn create_temp_directory(&self, _request: CreateTempDirectoryRequest) -> FsResult<OpenedTempDirectory> {
216 Err(FsError::new(
217 FsErrorKind::UnsupportedOperation,
218 FsOperation::CreateTemp,
219 "provider does not implement this operation",
220 ))
221 }
222}
223
224/// Builds a standard unsupported-operation error for a validated path request.
225fn unsupported(operation: FsOperation, path: &crate::path::Path) -> FsError {
226 FsError::new(
227 FsErrorKind::UnsupportedOperation,
228 operation,
229 "provider does not implement this operation",
230 )
231 .with_path(path.clone())
232}