loonfs_api/options.rs
1//! Per-operation option shapes shared by the runtime and client surfaces.
2//!
3//! `loonfs` (embedded runtime) and `loonfs-client` (HTTP client) expose the
4//! same semantic filesystem operations, so the options that parameterize them
5//! are defined once here and re-exported by both under their existing names.
6//! Keeping one definition is what stops the two surfaces from drifting a
7//! field apart.
8//!
9//! There is one type per operation, even where two of them currently hold the
10//! same fields: options follow the operation they parameterize, so a guard
11//! added to one is not silently offered on the others.
12//!
13//! These are plain in-process argument structs, not wire shapes: nothing here
14//! serializes. The request bodies that do cross the wire live in
15//! [`crate::v0`], and each surface resolves these options into one. A read's
16//! options reach the wire as query parameters the surface builds from them.
17
18use crate::{
19 ActorRef, AttributeKey, AttributeRevisionNo, AttributeValue, CommitId, DeleteDirectoryBehavior,
20 DestinationBehavior, InodeId, RevisionNo,
21};
22use std::collections::BTreeMap;
23
24/// Commit settings shared by every filesystem mutation.
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct CommitOptions {
27 /// Actor responsible for the commit, as supplied by the application.
28 pub actor: ActorRef,
29 /// Optional idempotency key. LoonFS generates one when this is `None`.
30 pub commit_id: Option<CommitId>,
31 /// Optional commit message. Changing it changes the commit identity.
32 pub message: Option<String>,
33}
34
35impl CommitOptions {
36 /// Creates settings with no commit ID or message.
37 pub fn new(actor: ActorRef) -> Self {
38 Self {
39 actor,
40 commit_id: None,
41 message: None,
42 }
43 }
44}
45
46/// Options for stating one path.
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct StatPathOptions {
49 /// Project the inode's attribute map and its revision onto the answer.
50 ///
51 /// Defaults to on. A stat answers for one path, and an attribute map is
52 /// capped at 64 KiB, so the cost of including it is bounded by the
53 /// request.
54 pub include_attributes: bool,
55}
56
57impl Default for StatPathOptions {
58 fn default() -> Self {
59 Self {
60 include_attributes: true,
61 }
62 }
63}
64
65/// Options for listing a directory.
66#[derive(Debug, Clone, PartialEq, Eq, Default)]
67pub struct ListPathEntriesOptions {
68 /// Project each entry's attribute map and its revision onto the answer.
69 ///
70 /// Defaults to off, and that default is what bounds a listing: a page
71 /// holds up to 1,000 entries and each attribute map may be 64 KiB, so an
72 /// always-on projection would put a 64 MiB response behind a request that
73 /// declares no byte budget anywhere. A caller that wants attributes for a
74 /// whole directory asks for them, and pages accordingly.
75 pub include_attributes: bool,
76}
77
78/// Options for writing and removing an inode's attributes.
79#[derive(Debug, Clone, PartialEq, Eq)]
80pub struct UpdateAttributesOptions {
81 /// Attributes to write. Each key replaces whatever the inode holds under
82 /// it; keys the inode holds and this map does not name are left alone.
83 pub set: BTreeMap<AttributeKey, AttributeValue>,
84 /// Keys to remove.
85 pub remove: Vec<AttributeKey>,
86 /// Actor, commit ID, and message.
87 pub commit: CommitOptions,
88 /// When set, the update applies only while the path still resolves to
89 /// this inode, so a raced rebinding fails instead of writing attributes
90 /// onto the wrong inode.
91 pub expected_inode_id: Option<InodeId>,
92 /// When set, the update applies only while the inode's attribute revision
93 /// is still this one. Every update carries its own revision guard either
94 /// way, so a concurrent update never merges silently.
95 pub expected_attributes_revision_no: Option<AttributeRevisionNo>,
96}
97
98impl UpdateAttributesOptions {
99 /// Creates an empty attribute update for this actor.
100 pub fn new(actor: ActorRef) -> Self {
101 Self {
102 set: BTreeMap::new(),
103 remove: Vec::new(),
104 commit: CommitOptions::new(actor),
105 expected_inode_id: None,
106 expected_attributes_revision_no: None,
107 }
108 }
109}
110
111/// Options for writing a file path.
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct PutFileOptions {
114 /// Create-only or replace-existing behavior.
115 pub behavior: DestinationBehavior,
116 /// Actor, commit ID, and message.
117 pub commit: CommitOptions,
118 /// Replace only while the file's current revision is still this one.
119 /// Requires `Replace` behavior; a raced write fails instead of stacking a
120 /// revision on state the caller never saw.
121 pub expected_revision_no: Option<RevisionNo>,
122}
123
124impl PutFileOptions {
125 /// Creates options that refuse to replace an existing file.
126 pub fn new(actor: ActorRef) -> Self {
127 Self {
128 behavior: DestinationBehavior::NoReplace,
129 commit: CommitOptions::new(actor),
130 expected_revision_no: None,
131 }
132 }
133}
134
135/// Options for creating a directory.
136#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct CreateDirectoryOptions {
138 /// Actor, commit ID, and message.
139 pub commit: CommitOptions,
140 /// Also create missing ancestor directories, like `put_file` does.
141 pub parents: bool,
142}
143
144impl CreateDirectoryOptions {
145 /// Creates options that do not create missing parent directories.
146 pub fn new(actor: ActorRef) -> Self {
147 Self {
148 commit: CommitOptions::new(actor),
149 parents: false,
150 }
151 }
152}
153
154/// Options for deleting a path.
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct DeleteOptions {
157 /// Directory delete behavior.
158 pub behavior: DeleteDirectoryBehavior,
159 /// Actor, commit ID, and message.
160 pub commit: CommitOptions,
161 /// When set, the delete applies only while the path still resolves to
162 /// this inode, so a raced rebinding fails instead of deleting the wrong
163 /// inode.
164 pub expected_inode_id: Option<InodeId>,
165}
166
167impl DeleteOptions {
168 /// Creates options for a non-recursive delete.
169 pub fn new(actor: ActorRef) -> Self {
170 Self {
171 behavior: DeleteDirectoryBehavior::NonRecursive,
172 commit: CommitOptions::new(actor),
173 expected_inode_id: None,
174 }
175 }
176}
177
178/// Options for moving a path.
179#[derive(Debug, Clone, PartialEq, Eq)]
180pub struct MoveOptions {
181 /// Create-only or replace-existing behavior for the destination.
182 pub behavior: DestinationBehavior,
183 /// Actor, commit ID, and message.
184 pub commit: CommitOptions,
185}
186
187impl MoveOptions {
188 /// Creates options that refuse to replace the destination.
189 pub fn new(actor: ActorRef) -> Self {
190 Self {
191 behavior: DestinationBehavior::NoReplace,
192 commit: CommitOptions::new(actor),
193 }
194 }
195}
196
197/// Options for copying a file path.
198#[derive(Debug, Clone, PartialEq, Eq)]
199pub struct CopyOptions {
200 /// Create-only or replace-existing behavior for the destination.
201 pub behavior: DestinationBehavior,
202 /// Actor, commit ID, and message.
203 pub commit: CommitOptions,
204}
205
206impl CopyOptions {
207 /// Creates options that refuse to replace the destination.
208 pub fn new(actor: ActorRef) -> Self {
209 Self {
210 behavior: DestinationBehavior::NoReplace,
211 commit: CommitOptions::new(actor),
212 }
213 }
214}
215
216/// Options for restoring a file revision by path.
217#[derive(Debug, Clone, PartialEq, Eq)]
218pub struct RestoreRevisionOptions {
219 /// Actor, commit ID, and message.
220 pub commit: CommitOptions,
221}
222
223impl RestoreRevisionOptions {
224 /// Creates restore options for this actor.
225 pub fn new(actor: ActorRef) -> Self {
226 Self {
227 commit: CommitOptions::new(actor),
228 }
229 }
230}
231
232/// Options for recovering a deleted file or subtree.
233#[derive(Debug, Clone, PartialEq, Eq)]
234pub struct UndeleteOptions {
235 /// Actor, commit ID, and message.
236 pub commit: CommitOptions,
237}
238
239impl UndeleteOptions {
240 /// Creates undelete options for this actor.
241 pub fn new(actor: ActorRef) -> Self {
242 Self {
243 commit: CommitOptions::new(actor),
244 }
245 }
246}