foyer_common/
code.rs

1// Copyright 2025 foyer Project Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::hash::{BuildHasher, BuildHasherDefault, Hash};
16
17use twox_hash::XxHash64;
18
19use crate::error::{Error, Result};
20
21/// Key trait for the in-memory cache.
22pub trait Key: Send + Sync + 'static + Hash + Eq {}
23/// Value trait for the in-memory cache.
24pub trait Value: Send + Sync + 'static {}
25
26impl<T: Send + Sync + 'static + std::hash::Hash + Eq> Key for T {}
27impl<T: Send + Sync + 'static> Value for T {}
28
29/// Hash builder trait.
30pub trait HashBuilder: BuildHasher + Send + Sync + 'static {}
31impl<T> HashBuilder for T where T: BuildHasher + Send + Sync + 'static {}
32
33/// The default hasher for foyer.
34///
35/// It is guaranteed that the hash results of the same key are the same across different runs.
36pub type DefaultHasher = BuildHasherDefault<XxHash64>;
37
38/// Key trait for the disk cache.
39pub trait StorageKey: Key + Code {}
40impl<T> StorageKey for T where T: Key + Code {}
41
42/// Value trait for the disk cache.
43pub trait StorageValue: Value + 'static + Code {}
44impl<T> StorageValue for T where T: Value + Code {}
45
46/// Encode/decode trait for key and value.
47///
48/// [`Code`] is required while working with foyer hybrid cache.
49///
50/// Some general types has already implemented [`Code`] by foyer, but the user needs to implement it for complex types.
51///
52/// Or, the user can enable `serde` feature for foyer.
53/// Then all types that implements `serde::Serialize` and `serde::de::DeserializeOwned` will be automatically
54/// implemented for [`Code`].
55pub trait Code {
56    /// Encode the object into a writer.
57    ///
58    /// NOTE:
59    ///
60    /// When implementing [`Code`], if [`std::io::Error`] or `bincode::Error` occurs during encoding,
61    /// please use [`Error::io_error`] or `Error::bincode_error` to convert it into [`Error`],
62    /// instead of manually creating an [`Error`]..
63    fn encode(&self, writer: &mut impl std::io::Write) -> Result<()>;
64
65    /// Decode the object from a reader.
66    ///
67    /// NOTE:
68    ///
69    /// When implementing [`Code`], if [`std::io::Error`] or `bincode::Error` occurs during decoding,
70    /// please use [`Error::io_error`] or `Error::bincode_error` to convert it into [`Error`],
71    /// instead of manually creating an [`Error`]..
72    fn decode(reader: &mut impl std::io::Read) -> Result<Self>
73    where
74        Self: Sized;
75
76    /// Estimated serialized size of the object.
77    ///
78    /// The estimated serialized size is used by selector between different disk cache engines.
79    fn estimated_size(&self) -> usize;
80}
81
82#[cfg(feature = "serde")]
83impl<T> Code for T
84where
85    T: serde::Serialize + serde::de::DeserializeOwned,
86{
87    fn encode(&self, writer: &mut impl std::io::Write) -> Result<()> {
88        bincode::serialize_into(writer, self).map_err(Error::bincode_error)
89    }
90
91    fn decode(reader: &mut impl std::io::Read) -> Result<Self> {
92        bincode::deserialize_from(reader).map_err(Error::bincode_error)
93    }
94
95    fn estimated_size(&self) -> usize {
96        bincode::serialized_size(self).unwrap() as usize
97    }
98}
99
100macro_rules! impl_serde_for_numeric_types {
101    ($($t:ty),*) => {
102        $(
103            #[cfg(not(feature = "serde"))]
104            impl Code for $t {
105                fn encode(&self, writer: &mut impl std::io::Write) -> Result<()> {
106                    writer.write_all(&self.to_le_bytes()).map_err(Error::io_error)
107                }
108
109                fn decode(reader: &mut impl std::io::Read) -> Result<Self> {
110                    let mut buf = [0u8; std::mem::size_of::<$t>()];
111                    reader.read_exact(&mut buf).map_err(Error::io_error)?;
112                    Ok(<$t>::from_le_bytes(buf))
113                }
114
115                fn estimated_size(&self) -> usize {
116                    std::mem::size_of::<$t>()
117                }
118            }
119        )*
120    };
121}
122
123macro_rules! for_all_numeric_types {
124    ($macro:ident) => {
125        $macro! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64}
126    };
127}
128
129for_all_numeric_types! { impl_serde_for_numeric_types }
130
131#[cfg(not(feature = "serde"))]
132impl Code for bool {
133    fn encode(&self, writer: &mut impl std::io::Write) -> Result<()> {
134        writer
135            .write_all(if *self { &[1u8] } else { &[0u8] })
136            .map_err(Error::io_error)
137    }
138
139    fn decode(reader: &mut impl std::io::Read) -> Result<Self>
140    where
141        Self: Sized,
142    {
143        let mut buf = [0u8; 1];
144        reader.read_exact(&mut buf).map_err(Error::io_error)?;
145        match buf[0] {
146            0 => Ok(false),
147            1 => Ok(true),
148            _ => Err(Error::new(crate::error::ErrorKind::Parse, "failed to parse bool").with_context("byte", buf[0])),
149        }
150    }
151
152    fn estimated_size(&self) -> usize {
153        1
154    }
155}
156
157#[cfg(not(feature = "serde"))]
158impl Code for Vec<u8> {
159    fn encode(&self, writer: &mut impl std::io::Write) -> Result<()> {
160        self.len().encode(writer)?;
161        writer.write_all(self).map_err(Error::io_error)
162    }
163
164    #[expect(clippy::uninit_vec)]
165    fn decode(reader: &mut impl std::io::Read) -> Result<Self>
166    where
167        Self: Sized,
168    {
169        let len = usize::decode(reader)?;
170        let mut v = Vec::with_capacity(len);
171        unsafe {
172            v.set_len(len);
173        }
174        reader.read_exact(&mut v).map_err(Error::io_error)?;
175        Ok(v)
176    }
177
178    fn estimated_size(&self) -> usize {
179        std::mem::size_of::<usize>() + self.len()
180    }
181}
182
183#[cfg(not(feature = "serde"))]
184impl Code for String {
185    fn encode(&self, writer: &mut impl std::io::Write) -> Result<()> {
186        self.len().encode(writer)?;
187        writer.write_all(self.as_bytes()).map_err(Error::io_error)
188    }
189
190    #[expect(clippy::uninit_vec)]
191    fn decode(reader: &mut impl std::io::Read) -> Result<Self>
192    where
193        Self: Sized,
194    {
195        let len = usize::decode(reader)?;
196        let mut v = Vec::with_capacity(len);
197        unsafe { v.set_len(len) };
198        reader.read_exact(&mut v).map_err(Error::io_error)?;
199        String::from_utf8(v)
200            .map_err(|e| Error::new(crate::error::ErrorKind::Parse, "failed to parse String").with_source(e))
201    }
202
203    fn estimated_size(&self) -> usize {
204        std::mem::size_of::<usize>() + self.len()
205    }
206}
207
208#[cfg(not(feature = "serde"))]
209impl Code for bytes::Bytes {
210    fn encode(&self, writer: &mut impl std::io::Write) -> Result<()> {
211        self.len().encode(writer)?;
212        writer.write_all(self).map_err(Error::io_error)
213    }
214
215    #[expect(clippy::uninit_vec)]
216    fn decode(reader: &mut impl std::io::Read) -> Result<Self>
217    where
218        Self: Sized,
219    {
220        let len = usize::decode(reader)?;
221        let mut v = Vec::with_capacity(len);
222        unsafe { v.set_len(len) };
223        reader.read_exact(&mut v).map_err(Error::io_error)?;
224        Ok(bytes::Bytes::from(v))
225    }
226
227    fn estimated_size(&self) -> usize {
228        std::mem::size_of::<usize>() + self.len()
229    }
230}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235
236    #[cfg(feature = "serde")]
237    mod serde {
238        use super::*;
239
240        #[test]
241        fn test_encode_overflow() {
242            let mut buf = [0u8; 4];
243            let e = 1u64.encode(&mut buf.as_mut()).unwrap_err();
244            assert_eq!(e.kind(), crate::error::ErrorKind::BufferSizeLimit);
245        }
246    }
247
248    #[cfg(not(feature = "serde"))]
249    mod non_serde {
250        use super::*;
251
252        #[test]
253        fn test_encode_overflow() {
254            let mut buf = [0u8; 4];
255            let e = 1u64.encode(&mut buf.as_mut()).unwrap_err();
256            assert_eq!(e.kind(), crate::error::ErrorKind::BufferSizeLimit);
257        }
258
259        macro_rules! impl_serde_test_for_numeric_types {
260            ($($t:ty),*) => {
261                paste::paste! {
262                    $(
263                        #[test]
264                        fn [<test_ $t _serde>]() {
265                            for a in [0 as $t, <$t>::MIN, <$t>::MAX] {
266                                let mut buf = vec![0xffu8; a.estimated_size()];
267                                a.encode(&mut buf.as_mut_slice()).unwrap();
268                                let b = <$t>::decode(&mut buf.as_slice()).unwrap();
269                                assert_eq!(a, b);
270                            }
271                        }
272                    )*
273                }
274            };
275        }
276
277        for_all_numeric_types! { impl_serde_test_for_numeric_types }
278
279        #[test]
280        fn test_bool_serde() {
281            let a = true;
282            let mut buf = vec![0xffu8; a.estimated_size()];
283            a.encode(&mut buf.as_mut_slice()).unwrap();
284            let b = bool::decode(&mut buf.as_slice()).unwrap();
285            assert_eq!(a, b);
286        }
287
288        #[test]
289        fn test_vec_u8_serde() {
290            let mut a = vec![0u8; 42];
291            rand::fill(&mut a[..]);
292            let mut buf = vec![0xffu8; a.estimated_size()];
293            a.encode(&mut buf.as_mut_slice()).unwrap();
294            let b = Vec::<u8>::decode(&mut buf.as_slice()).unwrap();
295            assert_eq!(a, b);
296        }
297
298        #[test]
299        fn test_string_serde() {
300            let a = "hello world".to_string();
301            let mut buf = vec![0xffu8; a.estimated_size()];
302            a.encode(&mut buf.as_mut_slice()).unwrap();
303            let b = String::decode(&mut buf.as_slice()).unwrap();
304            assert_eq!(a, b);
305        }
306
307        #[test]
308        fn test_bytes_serde() {
309            let mut a = vec![0u8; 42];
310            rand::fill(&mut a[..]);
311            let a = bytes::Bytes::from(a);
312            let mut buf = vec![0xffu8; a.estimated_size()];
313            a.encode(&mut buf.as_mut_slice()).unwrap();
314            let b = Vec::<u8>::decode(&mut buf.as_slice()).unwrap();
315            assert_eq!(a, b);
316        }
317    }
318}