Skip to main content

loonfs_api/
options.rs

1//! Per-operation options shared by the embedded runtime and HTTP client.
2
3use crate::{
4    AccessGrants, AccessRevisionNo, ActorId, AttributeKey, AttributeRevisionNo, AttributeValue,
5    CommitId, CommitPrecondition, DeleteDirectoryBehavior, DestinationBehavior, InodeId,
6    RevisionNo,
7};
8use crate::{SnapshotId, Subject};
9use std::collections::BTreeMap;
10
11/// Whether a path or inode read includes the attribute projection.
12#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
13pub enum AttributeInclusion {
14    /// Include the inode's attribute map and revision.
15    Include,
16    /// Omit the inode's attribute map and revision.
17    #[default]
18    Omit,
19}
20
21impl std::fmt::Display for AttributeInclusion {
22    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        formatter.write_str(match self {
24            Self::Include => "true",
25            Self::Omit => "false",
26        })
27    }
28}
29
30/// Commit settings shared by every filesystem mutation.
31#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
32#[serde(deny_unknown_fields)]
33pub struct CommitOptions {
34    /// Actor responsible for the commit, as supplied by the application.
35    pub actor_id: ActorId,
36    /// The subject whose grants authorize the commit.
37    #[serde(skip)]
38    pub subject: Option<Subject>,
39    /// The optional idempotency key, generated by LoonFS when absent.
40    pub commit_id: Option<CommitId>,
41    /// The optional commit message that forms part of the commit identity.
42    pub message: Option<String>,
43    /// Ordered admission conditions evaluated before any operations.
44    #[serde(default, skip_serializing_if = "Vec::is_empty")]
45    pub preconditions: Vec<CommitPrecondition>,
46}
47
48impl CommitOptions {
49    /// Creates settings with no commit ID or message.
50    pub fn new(actor: ActorId) -> Self {
51        Self {
52            actor_id: actor,
53            subject: None,
54            commit_id: None,
55            message: None,
56            preconditions: Vec::new(),
57        }
58    }
59}
60
61/// Options for stating one path.
62#[derive(Debug, Clone, PartialEq, Eq)]
63pub struct StatPathOptions {
64    /// Whether to include the inode's attribute map and revision, enabled by default.
65    pub include_attributes: AttributeInclusion,
66    /// Read the entry from this snapshot.
67    pub snapshot_id: Option<SnapshotId>,
68}
69
70impl Default for StatPathOptions {
71    fn default() -> Self {
72        Self {
73            include_attributes: AttributeInclusion::Include,
74            snapshot_id: None,
75        }
76    }
77}
78
79/// Options for listing a directory.
80#[derive(Debug, Clone, PartialEq, Eq, Default)]
81pub struct ListPathEntriesOptions {
82    /// Whether to include each entry's attribute map and revision, disabled by default.
83    pub include_attributes: AttributeInclusion,
84    /// Read the directory from this snapshot.
85    pub snapshot_id: Option<SnapshotId>,
86}
87
88/// Options for listing a directory's children by parent inode.
89#[derive(Debug, Clone, PartialEq, Eq, Default)]
90pub struct ListInodeChildrenOptions {
91    /// Whether to include each entry's attribute map and revision, disabled by default.
92    pub include_attributes: AttributeInclusion,
93    /// Read the directory from this snapshot.
94    pub snapshot_id: Option<SnapshotId>,
95}
96
97/// Options for writing and removing an inode's attributes.
98#[derive(Debug, Clone, PartialEq, Eq)]
99pub struct UpdateAttributesOptions {
100    /// The attributes to write, replacing values for matching keys and leaving other
101    /// keys unchanged.
102    pub set: BTreeMap<AttributeKey, AttributeValue>,
103    /// Keys to remove.
104    pub remove: Vec<AttributeKey>,
105    /// Actor, commit ID, and message.
106    pub commit: CommitOptions,
107    /// The inode that the path must still resolve to before the update.
108    pub expected_inode_id: Option<InodeId>,
109    /// With an inode precondition, the attribute revision that must still be current.
110    pub expected_attributes_revision_no: Option<AttributeRevisionNo>,
111}
112
113impl UpdateAttributesOptions {
114    /// Creates an empty attribute update for this actor.
115    pub fn new(actor: ActorId) -> Self {
116        Self {
117            set: BTreeMap::new(),
118            remove: Vec::new(),
119            commit: CommitOptions::new(actor),
120            expected_inode_id: None,
121            expected_attributes_revision_no: None,
122        }
123    }
124}
125
126/// Options for replacing an inode's access row.
127#[derive(Debug, Clone, PartialEq, Eq)]
128pub struct UpdateAccessOptions {
129    /// Whether the directory stops inheritance from its ancestors.
130    pub boundary: bool,
131    /// The complete direct grants after the update.
132    pub grants: AccessGrants,
133    /// Actor, commit ID, and message.
134    pub commit: CommitOptions,
135    /// The inode that the path must still resolve to before the update.
136    pub expected_inode_id: Option<InodeId>,
137    /// With an inode precondition, the access revision that must still be current.
138    pub expected_access_revision_no: Option<AccessRevisionNo>,
139}
140
141impl UpdateAccessOptions {
142    /// An update that replaces the grants and clears the boundary.
143    pub fn new(actor: ActorId, grants: AccessGrants) -> Self {
144        Self {
145            boundary: false,
146            grants,
147            commit: CommitOptions::new(actor),
148            expected_inode_id: None,
149            expected_access_revision_no: None,
150        }
151    }
152}
153
154/// Options for writing a file path.
155#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
156#[serde(deny_unknown_fields)]
157pub struct PutFileOptions {
158    /// Create-only or replace-existing behavior.
159    pub behavior: DestinationBehavior,
160    /// Actor, commit ID, and message.
161    pub commit: CommitOptions,
162    /// The inode that the path must still reference when using `Replace` behavior.
163    pub expected_inode_id: Option<InodeId>,
164    /// The revision that must still be current when using `Replace` behavior with
165    /// `expected_inode_id`.
166    pub expected_revision_no: Option<RevisionNo>,
167}
168
169impl PutFileOptions {
170    /// Creates options that refuse to replace an existing file.
171    pub fn new(actor: ActorId) -> Self {
172        Self {
173            behavior: DestinationBehavior::NoReplace,
174            commit: CommitOptions::new(actor),
175            expected_inode_id: None,
176            expected_revision_no: None,
177        }
178    }
179}
180
181/// Options for creating a directory.
182#[derive(Debug, Clone, PartialEq, Eq)]
183pub struct CreateDirectoryOptions {
184    /// Actor, commit ID, and message.
185    pub commit: CommitOptions,
186    /// Also create missing ancestor directories, like `put_file` does.
187    pub parents: bool,
188}
189
190impl CreateDirectoryOptions {
191    /// Creates options that do not create missing parent directories.
192    pub fn new(actor: ActorId) -> Self {
193        Self {
194            commit: CommitOptions::new(actor),
195            parents: false,
196        }
197    }
198}
199
200/// Options for deleting a path.
201#[derive(Debug, Clone, PartialEq, Eq)]
202pub struct DeleteOptions {
203    /// Directory delete behavior.
204    pub behavior: DeleteDirectoryBehavior,
205    /// Actor, commit ID, and message.
206    pub commit: CommitOptions,
207    /// The inode that the path must still resolve to before deletion.
208    pub expected_inode_id: Option<InodeId>,
209}
210
211impl DeleteOptions {
212    /// Creates options for a non-recursive delete.
213    pub fn new(actor: ActorId) -> Self {
214        Self {
215            behavior: DeleteDirectoryBehavior::NonRecursive,
216            commit: CommitOptions::new(actor),
217            expected_inode_id: None,
218        }
219    }
220}
221
222/// Options for moving a path.
223#[derive(Debug, Clone, PartialEq, Eq)]
224pub struct MoveOptions {
225    /// Create-only or replace-existing behavior for the destination.
226    pub behavior: DestinationBehavior,
227    /// Actor, commit ID, and message.
228    pub commit: CommitOptions,
229    /// The inode that the destination must still reference when using `Replace` behavior.
230    pub expected_destination_inode_id: Option<InodeId>,
231    /// The revision that must still be current when using `Replace` behavior with
232    /// `expected_destination_inode_id`.
233    pub expected_destination_revision_no: Option<RevisionNo>,
234}
235
236impl MoveOptions {
237    /// Creates options that refuse to replace the destination.
238    pub fn new(actor: ActorId) -> Self {
239        Self {
240            behavior: DestinationBehavior::NoReplace,
241            commit: CommitOptions::new(actor),
242            expected_destination_inode_id: None,
243            expected_destination_revision_no: None,
244        }
245    }
246}
247
248/// Options for copying a file path.
249#[derive(Debug, Clone, PartialEq, Eq)]
250pub struct CopyOptions {
251    /// Create-only or replace-existing behavior for the destination.
252    pub behavior: DestinationBehavior,
253    /// Actor, commit ID, and message.
254    pub commit: CommitOptions,
255    /// The inode that the destination must still reference when using `Replace` behavior.
256    pub expected_destination_inode_id: Option<InodeId>,
257    /// The revision that must still be current when using `Replace` behavior with
258    /// `expected_destination_inode_id`.
259    pub expected_destination_revision_no: Option<RevisionNo>,
260}
261
262impl CopyOptions {
263    /// Creates options that refuse to replace the destination.
264    pub fn new(actor: ActorId) -> Self {
265        Self {
266            behavior: DestinationBehavior::NoReplace,
267            commit: CommitOptions::new(actor),
268            expected_destination_inode_id: None,
269            expected_destination_revision_no: None,
270        }
271    }
272}
273
274/// Options for restoring a file revision by path.
275#[derive(Debug, Clone, PartialEq, Eq)]
276pub struct RestoreRevisionOptions {
277    /// Actor, commit ID, and message.
278    pub commit: CommitOptions,
279}
280
281impl RestoreRevisionOptions {
282    /// Creates restore options for this actor.
283    pub fn new(actor: ActorId) -> Self {
284        Self {
285            commit: CommitOptions::new(actor),
286        }
287    }
288}
289
290/// Options for recovering a deleted file or subtree.
291#[derive(Debug, Clone, PartialEq, Eq)]
292pub struct UndeleteOptions {
293    /// Actor, commit ID, and message.
294    pub commit: CommitOptions,
295}
296
297impl UndeleteOptions {
298    /// Creates undelete options for this actor.
299    pub fn new(actor: ActorId) -> Self {
300        Self {
301            commit: CommitOptions::new(actor),
302        }
303    }
304}
305
306/// Options for starting a direct multipart upload.
307#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
308pub struct DirectMultipartUploadOptions {
309    /// The byte length of every part except the last, or `None` for the server
310    /// default; providers allow at most 10,000 parts.
311    pub part_size_bytes: Option<u64>,
312}
313
314/// Selects the source state for a namespace fork.
315#[derive(Debug, Clone, PartialEq, Eq)]
316pub struct ForkNamespaceOptions {
317    /// Application-supplied actor creating the namespace.
318    pub actor_id: ActorId,
319    /// Fork from this live snapshot instead of the current head.
320    pub snapshot_id: Option<crate::SnapshotId>,
321}
322
323impl ForkNamespaceOptions {
324    /// Selects the current head.
325    pub fn new(actor_id: ActorId) -> Self {
326        Self {
327            actor_id,
328            snapshot_id: None,
329        }
330    }
331}