Skip to main content

fast_cache/storage/embedded_store_sharded/
views.rs

1use super::*;
2
3/// Read metadata for a value returned by a [`WorkerLocalEmbeddedStore`].
4///
5/// In the default safe build this owns a `Bytes` copy. With the `unsafe`
6/// feature it may hold a raw pointer into worker-owned storage; in that case
7/// the lifetime is tied to the exclusive `&mut WorkerLocalEmbeddedStore` borrow
8/// that produced it, and the `Rc` phantom keeps the value from being sent across
9/// threads.
10#[derive(Debug, Clone)]
11pub struct WorkerLocalReadSlice<'a> {
12    ptr: *const u8,
13    len: usize,
14    owned: Option<bytes::Bytes>,
15    _local: PhantomData<(&'a mut (), Rc<()>)>,
16}
17
18impl<'a> WorkerLocalReadSlice<'a> {
19    #[inline(always)]
20    pub(super) fn from_embedded(inner: EmbeddedReadSlice) -> Self {
21        let owned = inner.into_bytes();
22        Self {
23            ptr: owned.as_ptr(),
24            len: owned.len(),
25            owned: Some(owned),
26            _local: PhantomData,
27        }
28    }
29
30    #[inline(always)]
31    pub(super) fn from_local_slice(inner: &'a [u8]) -> Self {
32        #[cfg(not(feature = "unsafe"))]
33        {
34            let owned = bytes::Bytes::copy_from_slice(inner);
35            Self {
36                ptr: owned.as_ptr(),
37                len: owned.len(),
38                owned: Some(owned),
39                _local: PhantomData,
40            }
41        }
42
43        #[cfg(feature = "unsafe")]
44        Self {
45            ptr: inner.as_ptr(),
46            len: inner.len(),
47            owned: None,
48            _local: PhantomData,
49        }
50    }
51
52    #[inline(always)]
53    pub fn len(&self) -> usize {
54        self.len
55    }
56
57    #[inline(always)]
58    pub fn is_empty(&self) -> bool {
59        self.len == 0
60    }
61
62    #[inline(always)]
63    pub fn as_ptr(&self) -> *const u8 {
64        self.ptr
65    }
66
67    #[inline(always)]
68    pub fn as_slice(&self) -> &[u8] {
69        #[cfg(not(feature = "unsafe"))]
70        {
71            self.owned
72                .as_deref()
73                .expect("safe worker-local read slices are owned")
74        }
75
76        #[cfg(feature = "unsafe")]
77        {
78            if let Some(owned) = &self.owned {
79                return owned.as_ref();
80            }
81            // SAFETY: `WorkerLocalReadSlice` is only constructed from a slice tied
82            // to the caller's exclusive `&mut WorkerLocalEmbeddedStore` borrow or from an
83            // `EmbeddedReadSlice` protected by the existing embedded-store view
84            // invariants. The `Rc` phantom keeps the wrapper thread-local.
85            unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
86        }
87    }
88}
89
90/// Optional single-key read result from a worker-local store.
91#[derive(Debug)]
92pub struct WorkerLocalReadView<'a> {
93    pub(super) item: Option<WorkerLocalReadSlice<'a>>,
94}
95
96impl<'a> WorkerLocalReadView<'a> {
97    #[inline(always)]
98    pub fn is_hit(&self) -> bool {
99        self.item.is_some()
100    }
101
102    #[inline(always)]
103    pub fn len(&self) -> usize {
104        self.item.as_ref().map_or(0, WorkerLocalReadSlice::len)
105    }
106
107    #[inline(always)]
108    pub fn is_empty(&self) -> bool {
109        self.len() == 0
110    }
111
112    #[inline(always)]
113    pub fn slice(&self) -> Option<&[u8]> {
114        self.item.as_ref().map(WorkerLocalReadSlice::as_slice)
115    }
116
117    #[inline(always)]
118    pub fn slice_meta(&self) -> Option<WorkerLocalReadSlice<'a>> {
119        self.item.clone()
120    }
121}
122
123/// Batch read result whose item lifetimes are tied to one worker-local store borrow.
124#[derive(Debug)]
125pub struct WorkerLocalBatchReadView<'a> {
126    items: Vec<Option<WorkerLocalReadSlice<'a>>>,
127    hit_count: usize,
128    total_bytes: usize,
129}
130
131impl<'a> WorkerLocalBatchReadView<'a> {
132    #[inline(always)]
133    pub fn item_count(&self) -> usize {
134        self.items.len()
135    }
136
137    #[inline(always)]
138    pub fn hit_count(&self) -> usize {
139        self.hit_count
140    }
141
142    #[inline(always)]
143    pub fn total_bytes(&self) -> usize {
144        self.total_bytes
145    }
146
147    #[inline(always)]
148    pub fn all_hit(&self) -> bool {
149        self.hit_count == self.items.len()
150    }
151
152    #[inline(always)]
153    pub fn slice(&self, index: usize) -> Option<&[u8]> {
154        self.items
155            .get(index)
156            .and_then(|item| item.as_ref())
157            .map(WorkerLocalReadSlice::as_slice)
158    }
159
160    #[inline(always)]
161    pub fn slice_meta(&self, index: usize) -> Option<WorkerLocalReadSlice<'a>> {
162        self.items.get(index).cloned().flatten()
163    }
164
165    #[inline(always)]
166    pub fn lengths(&self) -> Vec<usize> {
167        self.items
168            .iter()
169            .map(|item| item.as_ref().map_or(0, WorkerLocalReadSlice::len))
170            .collect()
171    }
172}
173
174/// Session-key batch view returned by worker-local session APIs.
175pub type WorkerLocalSessionBatchView<'a> = WorkerLocalBatchReadView<'a>;
176
177pub(super) fn worker_local_batch_view_from_embedded<'a>(
178    items: Vec<Option<EmbeddedReadSlice>>,
179) -> WorkerLocalBatchReadView<'a> {
180    let mut converted = Vec::with_capacity(items.len());
181    let mut hit_count = 0usize;
182    let mut total_bytes = 0usize;
183    for item in items {
184        match item {
185            Some(slice) => {
186                hit_count += 1;
187                total_bytes += slice.len();
188                converted.push(Some(WorkerLocalReadSlice::from_embedded(slice)));
189            }
190            None => converted.push(None),
191        }
192    }
193    WorkerLocalBatchReadView {
194        items: converted,
195        hit_count,
196        total_bytes,
197    }
198}