skippy_cache/payload/
mod.rs1use std::{borrow::Cow, fmt};
2
3use anyhow::{Result, anyhow};
4
5mod blob_store;
6pub(super) mod bytes;
7
8pub use blob_store::{CacheBlobStore, CacheDedupeStats};
9pub use bytes::{CacheBytes, CacheBytesReconstructStats};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum ExactStatePayloadKind {
13 FullState,
14 RecurrentOnly,
15 KvRecurrent,
16}
17
18#[derive(Debug, Clone)]
19pub enum ExactStatePayload {
20 FullState {
21 bytes: CacheBytes,
22 },
23 RecurrentOnly {
24 recurrent: CacheBytes,
25 },
26 KvRecurrent {
27 kv: CacheBytes,
28 recurrent: CacheBytes,
29 },
30}
31
32impl ExactStatePayload {
33 pub fn full_state(bytes: Vec<u8>) -> Self {
34 Self::FullState {
35 bytes: CacheBytes::inline(bytes),
36 }
37 }
38
39 pub fn recurrent_only(recurrent: Vec<u8>) -> Self {
40 Self::RecurrentOnly {
41 recurrent: CacheBytes::inline(recurrent),
42 }
43 }
44
45 pub fn kv_recurrent(kv: Vec<u8>, recurrent: Vec<u8>) -> Self {
46 Self::KvRecurrent {
47 kv: CacheBytes::inline(kv),
48 recurrent: CacheBytes::inline(recurrent),
49 }
50 }
51
52 pub fn kind(&self) -> ExactStatePayloadKind {
53 match self {
54 Self::FullState { .. } => ExactStatePayloadKind::FullState,
55 Self::RecurrentOnly { .. } => ExactStatePayloadKind::RecurrentOnly,
56 Self::KvRecurrent { .. } => ExactStatePayloadKind::KvRecurrent,
57 }
58 }
59
60 pub fn byte_len(&self) -> u64 {
61 match self {
62 Self::FullState { bytes } => bytes.len(),
63 Self::RecurrentOnly { recurrent } => recurrent.len(),
64 Self::KvRecurrent { kv, recurrent } => kv.len().saturating_add(recurrent.len()),
65 }
66 }
67
68 pub fn recurrent_state_bytes(&self) -> Result<Cow<'_, [u8]>> {
69 match self {
70 Self::RecurrentOnly { recurrent } | Self::KvRecurrent { recurrent, .. } => {
71 recurrent.as_cow()
72 }
73 _ => Err(anyhow!("cache payload has no recurrent component")),
74 }
75 }
76
77 pub fn recurrent_state_bytes_timed(
78 &self,
79 ) -> Result<(Cow<'_, [u8]>, CacheBytesReconstructStats)> {
80 match self {
81 Self::RecurrentOnly { recurrent } | Self::KvRecurrent { recurrent, .. } => {
82 recurrent.as_cow_timed()
83 }
84 _ => Err(anyhow!("cache payload has no recurrent component")),
85 }
86 }
87
88 pub fn full_state_bytes_timed(&self) -> Result<(Cow<'_, [u8]>, CacheBytesReconstructStats)> {
89 match self {
90 Self::FullState { bytes } => bytes.as_cow_timed(),
91 _ => Err(anyhow!("cache payload is not full-state")),
92 }
93 }
94
95 pub fn kv_bytes(&self) -> Result<Option<Cow<'_, [u8]>>> {
96 match self {
97 Self::KvRecurrent { kv, .. } => Ok(Some(kv.as_cow()?)),
98 _ => Ok(None),
99 }
100 }
101
102 pub fn kv_bytes_timed(&self) -> Result<Option<(Cow<'_, [u8]>, CacheBytesReconstructStats)>> {
103 match self {
104 Self::KvRecurrent { kv, .. } => Ok(Some(kv.as_cow_timed()?)),
105 _ => Ok(None),
106 }
107 }
108
109 pub fn dedupe_into(self, blobs: &mut CacheBlobStore) -> (Self, CacheDedupeStats) {
110 match self {
111 Self::FullState { bytes } => {
112 let (bytes, stats) = blobs.store_bytes(bytes);
113 (Self::FullState { bytes }, stats)
114 }
115 Self::RecurrentOnly { recurrent } => {
116 let (recurrent, stats) = blobs.store_bytes(recurrent);
117 (Self::RecurrentOnly { recurrent }, stats)
118 }
119 Self::KvRecurrent { kv, recurrent } => {
120 let (kv, kv_stats) = blobs.store_bytes(kv);
121 let (recurrent, recurrent_stats) = blobs.store_bytes(recurrent);
122 (
123 Self::KvRecurrent { kv, recurrent },
124 kv_stats.saturating_add(recurrent_stats),
125 )
126 }
127 }
128 }
129
130 pub fn release_from(&self, blobs: &mut CacheBlobStore) {
131 match self {
132 Self::FullState { bytes } => blobs.release_bytes(bytes),
133 Self::RecurrentOnly { recurrent } => blobs.release_bytes(recurrent),
134 Self::KvRecurrent { kv, recurrent } => {
135 blobs.release_bytes(kv);
136 blobs.release_bytes(recurrent);
137 }
138 }
139 }
140}
141
142impl fmt::Display for ExactStatePayloadKind {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 match self {
145 Self::FullState => f.write_str("full-state"),
146 Self::RecurrentOnly => f.write_str("recurrent-only"),
147 Self::KvRecurrent => f.write_str("kv-recurrent"),
148 }
149 }
150}