wire/answer/prefix.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//! The system prompt one run was frozen with, and the general read of
7//! the content store it is recovered through.
8//!
9//! Both shapes live here because they are one question asked at two
10//! grains: a prefix answer is four store objects named by the record
11//! that froze them, and a content answer is one store object named by
12//! whoever holds its locator. A page that can draw the first can draw
13//! the second with no second vocabulary for "bytes this city kept".
14
15use kernel::{Address, B3Hash, Locator, RunId};
16use serde::{Deserialize, Serialize};
17
18/// The four slots of a frozen prefix, in the order they are sent.
19///
20/// Exhaustive and closed: the order is the cache economics, and a
21/// spelling a page had to match against a free string would let a
22/// segment arrive under a name nothing draws.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "snake_case")]
25#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
26pub enum PrefixSlot {
27 City,
28 Building,
29 Resident,
30 Run,
31}
32
33/// One document a segment was assembled from, as the assembler saw it.
34///
35/// `dropped` is what the per-slot budget cut off the end of that
36/// document, so a reader can tell a segment that carries a whole file
37/// from one that carries the first half of it. Zero is the ordinary
38/// case and is still reported, because "nothing was cut" is a fact and
39/// an absent field is not.
40#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
41#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
42pub struct PrefixSource {
43 pub addr: Address,
44 pub kept: u64,
45 pub dropped: u64,
46}
47
48/// One frozen segment, as a reader needs it.
49///
50/// `bytes` is what the record says the segment measured and `text` is
51/// what the store still holds, so the two disagreeing is itself the
52/// finding: `stored` false means the object is gone and the text is
53/// empty because nothing could be read, not because the segment was.
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
56pub struct PrefixSegment {
57 pub slot: PrefixSlot,
58 pub hash: B3Hash,
59 pub bytes: u64,
60 pub text: String,
61 pub stored: bool,
62 pub sources: Vec<PrefixSource>,
63}
64
65/// What one run was told before it said anything.
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
67#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
68pub struct PrefixAnswer {
69 pub run: RunId,
70 /// City, building, resident, run - always four, in that order.
71 pub segments: Vec<PrefixSegment>,
72}
73
74/// One object of the content store, cut to what travels.
75///
76/// The same bound and the same text judgement `Document` puts on a file
77/// in the tree, for the same reasons: bytes with a NUL in the head are
78/// not text, and showing them as text would show a reader something the
79/// object does not say.
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
81#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
82pub struct ContentAnswer {
83 /// The locator asked for, handed back: the wire carries no request
84 /// id, so a page matches an answer to its question by content.
85 pub locator: Locator,
86 pub text: String,
87 pub bytes: u64,
88 pub truncated: bool,
89 pub binary: bool,
90}