wire/answer/document.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! One file of the city, as a version (`crates/wire/spec/Answer/Document.lean` ยง8-69).
7//!
8//! A page that edits a file has to know which version it read, so the
9//! answer names it; and "nothing is here", "something is here that will
10//! not read" and "an empty file" are three answers, because a page offers
11//! a different next step for each. What the bytes are - text in which
12//! encoding, or not text - and where the first window ends are the
13//! `documents` crate's rules; this module only spells the answer.
14
15use documents::{Encoding, Format, Window};
16use kernel::{Address, B3Hash};
17use serde::{Deserialize, Serialize};
18
19/// One file, and what state it is in.
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
22pub struct DocumentAnswer {
23 pub at: Address,
24 pub state: DocumentState,
25}
26
27/// What stands at an address in the tree.
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
29#[serde(rename_all = "snake_case")]
30#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
31pub enum DocumentState {
32 /// No file is at this address; a save would create one.
33 Missing,
34 /// Something is here and will not read - a directory, a file this
35 /// process may not open - in the operating system's own words.
36 Unreadable { reason: String },
37 /// A file with no bytes. It has a version all the same, because an
38 /// empty file is something a save can be made on.
39 Empty { version: B3Hash, format: Format },
40 /// A file with bytes.
41 Held(Box<HeldDocument>),
42}
43
44/// A file with bytes: which version, how long, and what of it a reader
45/// is given now.
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
48pub struct HeldDocument {
49 /// The BLAKE3 digest of every byte, which is also the address the
50 /// content store gives them (`crates/documents/Spec.lean` D3).
51 pub version: B3Hash,
52 pub format: Format,
53 /// The whole version's length.
54 pub bytes: u64,
55 pub body: DocumentBody,
56}
57
58/// What the bytes of one version are to a reader.
59#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
60#[serde(rename_all = "snake_case")]
61#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
62pub enum DocumentBody {
63 /// Text in `encoding`. `head` is the first window, counted from byte
64 /// zero, a byte-order mark included as the text's first character.
65 Text {
66 encoding: Encoding,
67 head: Window,
68 coverage: Coverage,
69 },
70 /// Not text in any encoding this city reads: the version and its
71 /// length are all a reader is given.
72 Opaque,
73}
74
75/// How much of the version the first window holds.
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
77#[serde(rename_all = "snake_case")]
78#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
79pub enum Coverage {
80 /// All of it.
81 Whole,
82 /// Its head only. The version is in the content store, and
83 /// `Query::Range` reads the rest of it by its version.
84 Head,
85}