Skip to main content

kernel/tool/
writes.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//! What a call that ran may have written to the city's tree, as its tool
7//! can tell (`crates/kernel/spec/Tool.lean` §8-23).
8
9use super::Effect;
10use crate::Address;
11
12/// What one call, or every call since the last checkpoint, may have written.
13///
14/// A checkpoint stages what this names (`crates/runtime/Spec.lean` §8-45), so an
15/// answer narrower than the truth leaves a write no commit carries. Only
16/// a tool that knows every file it wrote answers `Paths`.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum Writes {
19    /// Nothing in the tree.
20    Nothing,
21    /// Exactly these files.
22    Paths(Vec<Address>),
23    /// Somewhere in the run's write domain, which the checkpoint then walks.
24    Domain,
25}
26
27impl Writes {
28    /// The default answer, read off the declared effect alone: only a
29    /// `Read` promises to leave the tree alone, and every other effect -
30    /// a command, a desk, a rule change, a spawned worktree - may write
31    /// where no argument says.
32    pub fn of(effect: &Effect) -> Self {
33        match effect {
34            Effect::Read => Self::Nothing,
35            Effect::Write { .. }
36            | Effect::Egress
37            | Effect::Connector { .. }
38            | Effect::Spawn
39            | Effect::Govern
40            | Effect::AttachUserBrowser { .. }
41            | Effect::Spend => Self::Domain,
42        }
43    }
44
45    /// Both answers at once: `Domain` absorbs everything, `Nothing` adds
46    /// nothing, and two sets of paths join without duplicates.
47    #[must_use]
48    pub fn and(self, other: Self) -> Self {
49        match (self, other) {
50            (Self::Domain, _) | (_, Self::Domain) => Self::Domain,
51            (Self::Nothing, only) | (only, Self::Nothing) => only,
52            (Self::Paths(mut these), Self::Paths(those)) => {
53                for path in those {
54                    if !these.contains(&path) {
55                        these.push(path);
56                    }
57                }
58                Self::Paths(these)
59            }
60        }
61    }
62}