Skip to main content

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}