Skip to main content

hydracache_core/
codec.rs

1use bytes::Bytes;
2use serde::{de::DeserializeOwned, Serialize};
3
4use crate::{CacheError, Result};
5
6/// Serialization boundary for cached values.
7///
8/// Implement this trait to replace the default [`PostcardCodec`].
9///
10/// # Example
11///
12/// ```rust
13/// use hydracache_core::{CacheCodec, PostcardCodec};
14/// use serde::{Deserialize, Serialize};
15///
16/// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
17/// struct User {
18///     id: u64,
19/// }
20///
21/// let codec = PostcardCodec;
22/// let bytes = codec.encode(&User { id: 1 }).unwrap();
23/// let decoded: User = codec.decode(&bytes).unwrap();
24///
25/// assert_eq!(decoded, User { id: 1 });
26/// ```
27pub trait CacheCodec: Clone + Send + Sync + 'static {
28    /// Encode a typed value into bytes.
29    fn encode<T>(&self, value: &T) -> Result<Bytes>
30    where
31        T: Serialize;
32
33    /// Decode bytes back into a typed value.
34    fn decode<T>(&self, bytes: &Bytes) -> Result<T>
35    where
36        T: DeserializeOwned;
37}
38
39/// Default compact binary codec for v0.
40///
41/// `PostcardCodec` is compact and works well for local cache values that derive
42/// `serde::Serialize` and `serde::Deserialize`.
43#[derive(Debug, Clone, Copy, Default)]
44pub struct PostcardCodec;
45
46impl CacheCodec for PostcardCodec {
47    fn encode<T>(&self, value: &T) -> Result<Bytes>
48    where
49        T: Serialize,
50    {
51        postcard::to_allocvec(value)
52            .map(Bytes::from)
53            .map_err(|source| CacheError::Encode(source.to_string()))
54    }
55
56    fn decode<T>(&self, bytes: &Bytes) -> Result<T>
57    where
58        T: DeserializeOwned,
59    {
60        postcard::from_bytes(bytes).map_err(|source| CacheError::Decode(source.to_string()))
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use serde::ser::{Serialize, Serializer};
67
68    use super::*;
69
70    struct FailingSerialize;
71
72    impl Serialize for FailingSerialize {
73        fn serialize<S>(&self, _serializer: S) -> std::result::Result<S::Ok, S::Error>
74        where
75            S: Serializer,
76        {
77            Err(serde::ser::Error::custom("intentional encode failure"))
78        }
79    }
80
81    #[test]
82    fn postcard_codec_reports_encode_errors() {
83        let error = PostcardCodec.encode(&FailingSerialize).unwrap_err();
84
85        assert!(matches!(error, CacheError::Encode(_)));
86    }
87
88    #[test]
89    fn postcard_codec_default_is_available() {
90        let codec = PostcardCodec;
91        let default_codec = PostcardCodec;
92
93        assert_eq!(format!("{codec:?}"), format!("{default_codec:?}"));
94    }
95}