Skip to main content

fast_cache/storage/embedded_store/
views.rs

1/// One stable byte slice captured during a batch read.
2///
3/// The slice owns a `bytes::Bytes` handle. Older versions stored raw pointers
4/// into shard memory and relied on a separate guard to keep those pointers
5/// valid; that made `slice_meta()` too easy to misuse. Keeping the backing
6/// bytes here preserves the same read API while making the metadata object
7/// independently memory-safe.
8#[derive(Debug, Clone)]
9pub struct EmbeddedReadSlice {
10    pub(super) bytes: bytes::Bytes,
11}
12
13impl EmbeddedReadSlice {
14    #[inline(always)]
15    pub(super) fn from_slice(value: &[u8]) -> Self {
16        Self {
17            bytes: bytes::Bytes::copy_from_slice(value),
18        }
19    }
20
21    #[inline(always)]
22    pub(crate) fn into_bytes(self) -> bytes::Bytes {
23        self.bytes
24    }
25
26    #[inline(always)]
27    pub fn len(&self) -> usize {
28        self.bytes.len()
29    }
30
31    #[inline(always)]
32    pub fn is_empty(&self) -> bool {
33        self.bytes.is_empty()
34    }
35
36    #[inline(always)]
37    pub fn as_ptr(&self) -> *const u8 {
38        self.bytes.as_ptr()
39    }
40
41    #[inline(always)]
42    pub fn as_slice(&self) -> &[u8] {
43        self.bytes.as_ref()
44    }
45}
46
47/// Owned single-value read view.
48///
49/// The view carries its own `bytes::Bytes` handle, so `slice()` and
50/// `slice_meta()` remain valid independently of later store mutations.
51#[derive(Debug)]
52pub struct EmbeddedReadView {
53    pub(super) item: Option<EmbeddedReadSlice>,
54}
55
56impl EmbeddedReadView {
57    #[inline(always)]
58    pub fn is_hit(&self) -> bool {
59        self.item.is_some()
60    }
61
62    #[inline(always)]
63    pub fn len(&self) -> usize {
64        self.item.as_ref().map_or(0, EmbeddedReadSlice::len)
65    }
66
67    #[inline(always)]
68    pub fn is_empty(&self) -> bool {
69        self.len() == 0
70    }
71
72    #[inline(always)]
73    pub fn slice(&self) -> Option<&[u8]> {
74        self.item.as_ref().map(EmbeddedReadSlice::as_slice)
75    }
76
77    #[inline(always)]
78    pub fn slice_meta(&self) -> Option<EmbeddedReadSlice> {
79        self.item.clone()
80    }
81}
82
83/// Owned batch read view.
84///
85/// Each hit carries its own `bytes::Bytes` handle. This keeps the public view
86/// API memory-safe even when callers hold metadata longer than the store.
87#[derive(Debug)]
88pub struct EmbeddedBatchReadView {
89    pub(super) items: Vec<Option<EmbeddedReadSlice>>,
90    pub(super) hit_count: usize,
91    pub(super) total_bytes: usize,
92}
93
94impl EmbeddedBatchReadView {
95    #[inline(always)]
96    pub fn item_count(&self) -> usize {
97        self.items.len()
98    }
99
100    #[inline(always)]
101    pub fn hit_count(&self) -> usize {
102        self.hit_count
103    }
104
105    #[inline(always)]
106    pub fn total_bytes(&self) -> usize {
107        self.total_bytes
108    }
109
110    #[inline(always)]
111    pub fn all_hit(&self) -> bool {
112        self.hit_count == self.items.len()
113    }
114
115    #[inline(always)]
116    pub fn slice(&self, index: usize) -> Option<&[u8]> {
117        self.items
118            .get(index)
119            .and_then(|item| item.as_ref())
120            .map(EmbeddedReadSlice::as_slice)
121    }
122
123    #[inline(always)]
124    pub fn slice_meta(&self, index: usize) -> Option<EmbeddedReadSlice> {
125        self.items.get(index).cloned().flatten()
126    }
127
128    #[inline(always)]
129    pub fn lengths(&self) -> Vec<usize> {
130        self.items
131            .iter()
132            .map(|item| item.as_ref().map_or(0, EmbeddedReadSlice::len))
133            .collect()
134    }
135}
136
137/// Session-scoped owned batch view.
138///
139/// This is currently just a clearer alias for the generic batch guard used by
140/// the Python API and the LLM benchmark path.
141pub type EmbeddedSessionBatchView = EmbeddedBatchReadView;
142
143/// Owned single-value read view for the owned-worker embedded path.
144#[derive(Debug)]
145pub struct OwnedEmbeddedReadView {
146    pub(super) item: Option<EmbeddedReadSlice>,
147}
148
149impl OwnedEmbeddedReadView {
150    #[inline(always)]
151    pub fn is_hit(&self) -> bool {
152        self.item.is_some()
153    }
154
155    #[inline(always)]
156    pub fn len(&self) -> usize {
157        self.item.as_ref().map_or(0, EmbeddedReadSlice::len)
158    }
159
160    #[inline(always)]
161    pub fn is_empty(&self) -> bool {
162        self.len() == 0
163    }
164
165    #[inline(always)]
166    pub fn slice(&self) -> Option<&[u8]> {
167        self.item.as_ref().map(EmbeddedReadSlice::as_slice)
168    }
169
170    #[inline(always)]
171    pub fn slice_meta(&self) -> Option<EmbeddedReadSlice> {
172        self.item.clone()
173    }
174}
175
176/// Owned batch read view for the owned-worker embedded path.
177#[derive(Debug)]
178pub struct OwnedEmbeddedBatchReadView {
179    pub(super) items: Vec<Option<EmbeddedReadSlice>>,
180    pub(super) hit_count: usize,
181    pub(super) total_bytes: usize,
182}
183
184impl OwnedEmbeddedBatchReadView {
185    #[inline(always)]
186    pub fn item_count(&self) -> usize {
187        self.items.len()
188    }
189
190    #[inline(always)]
191    pub fn hit_count(&self) -> usize {
192        self.hit_count
193    }
194
195    #[inline(always)]
196    pub fn total_bytes(&self) -> usize {
197        self.total_bytes
198    }
199
200    #[inline(always)]
201    pub fn all_hit(&self) -> bool {
202        self.hit_count == self.items.len()
203    }
204
205    #[inline(always)]
206    pub fn slice(&self, index: usize) -> Option<&[u8]> {
207        self.items
208            .get(index)
209            .and_then(|item| item.as_ref())
210            .map(EmbeddedReadSlice::as_slice)
211    }
212
213    #[inline(always)]
214    pub fn slice_meta(&self, index: usize) -> Option<EmbeddedReadSlice> {
215        self.items.get(index).cloned().flatten()
216    }
217
218    #[inline(always)]
219    pub fn lengths(&self) -> Vec<usize> {
220        self.items
221            .iter()
222            .map(|item| item.as_ref().map_or(0, EmbeddedReadSlice::len))
223            .collect()
224    }
225}
226
227pub type OwnedEmbeddedSessionBatchView = OwnedEmbeddedBatchReadView;
228
229/// Owned packed-session view for the owned-worker embedded path.
230///
231/// The packed payload is copied into an owned `bytes::Bytes` buffer so the
232/// offset table stays valid without a raw pointer back into the worker shard.
233#[derive(Debug)]
234pub struct OwnedEmbeddedSessionPackedView {
235    pub(super) buffer: EmbeddedReadSlice,
236    pub(super) offsets: Vec<usize>,
237    pub(super) lengths: Vec<usize>,
238    pub(super) hit_count: usize,
239    pub(super) total_bytes: usize,
240}
241
242impl OwnedEmbeddedSessionPackedView {
243    #[inline(always)]
244    pub fn item_count(&self) -> usize {
245        self.offsets.len()
246    }
247
248    #[inline(always)]
249    pub fn hit_count(&self) -> usize {
250        self.hit_count
251    }
252
253    #[inline(always)]
254    pub fn total_bytes(&self) -> usize {
255        self.total_bytes
256    }
257
258    #[inline(always)]
259    pub fn all_hit(&self) -> bool {
260        self.hit_count == self.offsets.len()
261    }
262
263    #[inline(always)]
264    pub fn buffer(&self) -> &[u8] {
265        self.buffer.as_slice()
266    }
267
268    #[inline(always)]
269    pub fn buffer_meta(&self) -> EmbeddedReadSlice {
270        self.buffer.clone()
271    }
272
273    #[inline(always)]
274    pub fn offsets(&self) -> &[usize] {
275        &self.offsets
276    }
277
278    #[inline(always)]
279    pub fn lengths(&self) -> &[usize] {
280        &self.lengths
281    }
282}