Skip to main content

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}