Skip to main content

backhopper_core/model/
cache.rs

1// Copyright (C) 2026 Michael S. Klishin and Contributors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// See LICENSE-APACHE and LICENSE-MIT for details.
4
5//! Wire payloads for the `cache` verb group.
6//!
7//! The data behind these types is produced by `backhopper-cache`
8//! (which depends on this crate); the shapes live here so the schema
9//! generator and the driver see them without a dependency cycle.
10
11use serde::{Deserialize, Serialize};
12
13/// Which workspace cache an entry belongs to.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
15#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
16#[serde(rename_all = "snake_case")]
17pub enum CacheLevel {
18    /// `.verdict_cache/by-input/`: SHA-keyed verdict entries.
19    ByInput,
20    /// `.verdict_cache/by-content/`: content-keyed verdict entries.
21    ByContent,
22}
23
24impl CacheLevel {
25    #[must_use]
26    pub fn as_str(self) -> &'static str {
27        match self {
28            Self::ByInput => "by-input",
29            Self::ByContent => "by-content",
30        }
31    }
32}
33
34/// Per-level counters inside `cache stats`.
35#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
36#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
37pub struct CacheLevelStats {
38    pub entries: u64,
39    pub bytes: u64,
40}
41
42/// The `cache stats` payload.
43#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
44#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
45pub struct CacheStatsPayload {
46    pub by_input: CacheLevelStats,
47    pub by_content: CacheLevelStats,
48    /// `by-input` entries created as aliases of a content-level hit.
49    pub aliases: u64,
50    pub total_bytes: u64,
51    /// RFC3339 write times of the oldest and newest entries across
52    /// every level; absent when all caches are empty.
53    #[serde(default, skip_serializing_if = "Option::is_none")]
54    pub oldest_entry_at: Option<String>,
55    #[serde(default, skip_serializing_if = "Option::is_none")]
56    pub newest_entry_at: Option<String>,
57}
58
59/// One row in `cache list`.
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
62pub struct CacheListRow {
63    /// The entry's key hash (the file-name stem after the format
64    /// prefix); unique prefixes of it address entries in `show` and
65    /// `evict`.
66    pub key: String,
67    pub level: CacheLevel,
68    /// The evaluated commit, for verdict entries that carry one.
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub commit: Option<String>,
71    /// The series or pin target, when the pre-image names one.
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    pub series: Option<String>,
74    pub age_days: u32,
75    pub bytes: u64,
76    /// True for `by-input` entries created from a content-level hit.
77    #[serde(default)]
78    pub alias: bool,
79}
80
81/// The `cache list` payload.
82#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
83#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
84pub struct CacheListPayload {
85    pub rows: Vec<CacheListRow>,
86}
87
88/// The `cache show` payload: one entry, pre-image included.
89#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
90#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
91pub struct CacheShowPayload {
92    pub key: String,
93    pub level: CacheLevel,
94    pub created_at: String,
95    pub age_days: u32,
96    pub bytes: u64,
97    /// True for `by-input` entries created as aliases of a
98    /// content-level hit.
99    #[serde(default)]
100    pub alias: bool,
101    /// The canonical-JSON key pre-image stored inside the entry.
102    pub key_inputs: serde_json::Value,
103    /// Verdict counts for the stored evaluation.
104    #[serde(default, skip_serializing_if = "Option::is_none")]
105    pub verdict_summary: Option<serde_json::Value>,
106    /// The full stored value, under `--full` only.
107    #[serde(default, skip_serializing_if = "Option::is_none")]
108    pub value: Option<serde_json::Value>,
109}
110
111/// Payload for `cache evict`, `cache prune`, and `cache clear`.
112#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
113#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
114pub struct CacheMutationPayload {
115    pub removed_entries: u64,
116    pub removed_bytes: u64,
117}