Skip to main content

loonfs_api/
lib.rs

1//! Wire types and durable-format codecs for LoonFS.
2//!
3//! Everything that crosses a process or storage boundary is defined here:
4//! validated identifier and path types at the crate root, the versioned HTTP
5//! protocol shapes in [`v0`], and the durable storage formats in [`wire`]
6//! (WAL segments, metadata SSTs, namespace manifests, and control objects).
7//! Other LoonFS crates depend on this one for vocabulary; it depends on none
8//! of them.
9//!
10//! One module here is deliberately not a boundary format: [`options`] holds
11//! the per-operation argument structs that the embedded runtime and the HTTP
12//! client both expose. They parameterize the same semantic operations on both
13//! surfaces, so this crate — the shared vocabulary — owns the single
14//! definition rather than each surface keeping its own copy to drift.
15//!
16//! One module is a function rather than a shape: `commit_identity` computes
17//! the durable fingerprint of a mutation. It lives here for the same reason
18//! the operation language does — the engine that stamps a fingerprint on a
19//! commit receipt and the client that recomputes one to prove a retry is the
20//! same request must produce identical values, so there is one implementation
21//! and no second reading of the rules.
22//!
23//! Module rule: v0 HTTP shapes live in [`v0`]; the crate root keeps the
24//! ids/paths/errors/wire-format modules and re-exports the common v0
25//! surface as a curated explicit list below.
26
27#![warn(missing_docs)]
28
29mod capability;
30mod commit_identity;
31mod content;
32mod control;
33mod digest;
34mod envelope;
35mod error;
36mod hex;
37mod ids;
38mod manifest;
39mod name_policy;
40pub mod options;
41mod pagination;
42mod path;
43mod sst_blocks;
44pub mod v0;
45mod wal;
46
47pub mod wire {
48    //! Durable wire formats grouped by their owning format family.
49
50    pub mod hex {
51        //! Lowercase hexadecimal primitives shared by durable codecs.
52
53        pub use crate::hex::*;
54    }
55
56    pub mod manifest {
57        //! Namespace-manifest envelopes, rows, and key constructors.
58
59        pub use crate::manifest::*;
60    }
61
62    pub mod control {
63        //! Mutable namespace control-object envelopes and payloads.
64
65        pub use crate::control::*;
66    }
67
68    pub mod envelope {
69        //! The shared durable envelope codec: probe, validation rules, JSON
70        //! codec, and the one error vocabulary every family reports through.
71        //!
72        //! Published so a durable format outside this crate — a first-party
73        //! extension's own objects — parameterizes the same codec instead of
74        //! copying it and drifting from the rules in section 4 of the format
75        //! spec.
76
77        pub use crate::envelope::*;
78    }
79
80    pub mod sst_blocks {
81        //! Metadata SST block handles, builders, and codecs.
82
83        pub use crate::sst_blocks::*;
84    }
85
86    pub mod wal {
87        //! WAL segment envelopes, records, and codecs.
88
89        pub use crate::wal::*;
90    }
91}
92
93pub use capability::{
94    CapabilityDocument, CapabilityDocumentError, FEATURE_DOWNLOADS_DIRECT_GET,
95    FEATURE_NAMESPACES_CREATE, FEATURE_NAMESPACES_DELETE, FEATURE_NAMESPACES_FORK,
96    FEATURE_QUERY_GREP, FEATURE_UPLOADS_DIRECT_MULTIPART, FEATURE_UPLOADS_DIRECT_PUT,
97    LIMIT_COMMIT_MAX_CONTENT_TOKENS, LIMIT_COMMIT_MAX_EXTERNAL_CONTENT_REFS,
98    LIMIT_COMMIT_MAX_MESSAGE_BYTES, LIMIT_COMMIT_MAX_OPERATIONS, LIMIT_DOWNLOAD_MAX_CONCURRENT,
99    LIMIT_DOWNLOAD_MAX_CONTENT_BYTES, LIMIT_GC_MIN_GRACE_WINDOW_MS, LIMIT_PAGINATION_DEFAULT,
100    LIMIT_PAGINATION_MAX, LIMIT_QUERY_GREP_DEFAULT, LIMIT_QUERY_GREP_MAX,
101    LIMIT_QUERY_GREP_SCAN_BUDGET_FILES, LIMIT_QUERY_GREP_TAIL_BUDGET_FILES,
102    LIMIT_UPLOAD_MAX_CONCURRENT, LIMIT_UPLOAD_MAX_CONTENT_BYTES, PROFILE_ADMIN_V0, PROFILE_CORE_V0,
103    PROFILE_QUERY_V0, PROTOCOL_VERSION,
104};
105pub use commit_identity::{
106    put_retry_fingerprint, semantic_commit_fingerprint, SemanticFingerprintError,
107};
108pub use content::{
109    ChecksumAlgorithm, ContentRef, ContentRefKind, ContentRefValidationError, Crc64Nvme, Sha256,
110    StorageChecksum, StreamingChecksum,
111};
112pub use digest::sha256_digest;
113pub use error::{ErrorCode, ErrorKind};
114pub use ids::{
115    generated_id, manifest_object_id_manifest_id, wal_segment_id_start_seq, ChangeSeq,
116    CheckpointId, CommitId, CommitIdValidationError, ContentId, ContentStoreId,
117    GeneratedIdValidationError, IndexSegmentId, InodeId, InodeKind, ManifestId, ManifestObjectId,
118    MetadataTableId, NameKey, NameKeyValidationError, NamespaceId, NamespaceIdValidationError,
119    RevisionNo, UploadId, WalSegmentId, WriterEpoch, MAX_ID_BYTES, MAX_NAME_KEY_BYTES,
120    ROOT_INODE_ID,
121};
122pub use name_policy::name_key_for_display_name;
123pub use pagination::{
124    decode_cursor, decode_namespace_cursor, encode_cursor, DirectoryPageCursor, EffectiveLimit,
125    FileRevisionsPageCursor, GrepPageCursor, LimitError, NamespaceCursor, NamespaceCursorError,
126    Page, PageCursor, PageCursorError, PageRequest, PaginationPolicy, PaginationPolicyError,
127    TrashPageCursor, DEFAULT_MAX_PAGE_LIMIT, DEFAULT_PAGE_LIMIT, PAGE_CURSOR_VERSION,
128};
129pub use path::{
130    AbsolutePath, DisplayName, PathComponent, PathError, MAX_DISPLAY_NAME_BYTES, MAX_PATH_BYTES,
131    MAX_PATH_DEPTH,
132};
133
134// Curated root re-exports of the common v0 HTTP surface. v0 HTTP shapes live
135// in `v0`; add here only what most consumers touch.
136pub use v0::{
137    AdvanceRetentionResponse, ApiError, AuthoritativeFileBytes, AuthoritativePathEntry,
138    CheckpointOwnerSummary, CheckpointSummary, CommitRequest, CommitResponse,
139    CreateCheckpointRequest, CreateCheckpointResponse, CreateNamespaceRequest,
140    DeleteDirectoryBehavior, DeleteNamespaceResponse, DestinationBehavior, ErrorDetails,
141    FileRevision, FilesystemOperation, FlushWalOutcome, FlushWalResponse, ForkNamespaceRequest,
142    GcRequest, GcResponse, GrepMatch, GrepRequest, GrepResponse, ListCheckpointsResponse,
143    ListFileRevisionsResponse, ListPathEntriesResponse, ListTrashResponse, MaintenanceStepKind,
144    MaintenanceStepRequest, MaintenanceStepResponse, NamespaceStatusResponse, NamespaceSummary,
145    ReleaseCheckpointResponse, ReorganizeStepOutcome, RetainedCandidates, RetainedReason,
146    TrashEntry, WalFlushStepOutcome,
147};
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    #[test]
154    fn curated_root_exports_cover_common_public_types() {
155        let namespace_id = NamespaceId::parse("demo").expect("valid namespace id");
156        let commit_id = CommitId::generate();
157        let path = AbsolutePath::parse("/docs/report.txt").expect("valid path");
158        let display_name = DisplayName::parse("Report.txt").expect("valid display name");
159        let name_key = NameKey::for_display_name(&display_name);
160        let content_ref = ContentRef::blob_v1(ContentId::generate(), b"hello");
161
162        assert_eq!(namespace_id.as_str(), "demo");
163        assert!(commit_id.as_str().starts_with("c_"));
164        assert_eq!(path.as_str(), "/docs/report.txt");
165        assert_eq!(name_key.as_str(), "report.txt");
166        assert_eq!(content_ref.size_bytes, 5);
167    }
168
169    #[test]
170    fn durable_protocol_types_are_available_under_wire() {
171        let _head = wire::control::HeadState::initial(
172            NamespaceId::parse("demo").expect("valid namespace id"),
173            ContentStoreId::parse("cs_0123456789abcdef0123456789abcdef")
174                .expect("valid content store id"),
175        );
176        let _wal_delta = wire::wal::WalDelta::TombstoneSubtree {
177            delta_index: 0,
178            root_inode_id: InodeId(1),
179            parent_inode_id: None,
180            name_key: None,
181            display_name: None,
182        };
183        let _manifest_row = wire::manifest::MetadataRow::Tombstone {
184            root_inode_id: InodeId(1),
185            tombstone_seq: ChangeSeq(1),
186            tombstone_delta_index: 0,
187            action: wire::manifest::TombstoneRowAction::Set,
188            deleted_at_ms: 4_000,
189            parent_inode_id: None,
190            name_key: None,
191            display_name: None,
192        };
193    }
194}