Skip to main content

lance_core/cache/
codec.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4//! Serialization codecs for cache entries.
5//!
6//! Implement [`CacheCodecImpl`] on concrete types, then use
7//! [`CacheCodec::from_impl`] to produce a type-erased codec for the cache.
8
9use std::sync::Arc;
10
11use bytes::Bytes;
12
13use crate::Result;
14
15// ---------------------------------------------------------------------------
16// CacheCodecImpl — trait for serializable cache entry types
17// ---------------------------------------------------------------------------
18
19/// Serialization trait for cache entries.
20///
21/// **Experimental**: the serialized format is not stable and may change
22/// between releases without notice.
23///
24/// Implement this on concrete types that need to survive serialization
25/// through a persistent cache backend. Then wire it into a [`CacheKey`](super::CacheKey)
26/// via [`CacheCodec::from_impl`]:
27///
28/// ```ignore
29/// impl CacheCodecImpl for MyData {
30///     fn serialize(&self, w: &mut dyn Write) -> Result<()> { /* ... */ }
31///     fn deserialize(data: &Bytes) -> Result<Self> { /* ... */ }
32/// }
33///
34/// impl CacheKey for MyDataKey {
35///     type ValueType = MyData;
36///     fn codec() -> Option<CacheCodec> {
37///         Some(CacheCodec::from_impl::<MyData>())
38///     }
39///     // ...
40/// }
41/// ```
42pub trait CacheCodecImpl: Send + Sync {
43    fn serialize(&self, writer: &mut dyn std::io::Write) -> Result<()>;
44
45    fn deserialize(data: &Bytes) -> Result<Self>
46    where
47        Self: Sized;
48}
49
50// ---------------------------------------------------------------------------
51// CacheCodec — type-erased codec passed to backends
52// ---------------------------------------------------------------------------
53
54pub(crate) type ArcAny = Arc<dyn std::any::Any + Send + Sync>;
55
56/// Type-erased codec for serializing and deserializing cache entries.
57///
58/// `CacheCodec` is two plain function pointers — it is `Copy` and has no
59/// heap allocation. Construct one via [`CacheCodec::from_impl`] for types
60/// that implement [`CacheCodecImpl`], or [`CacheCodec::new`] for custom
61/// cases (e.g. when the orphan rule prevents a direct impl).
62#[derive(Copy, Clone)]
63pub struct CacheCodec {
64    pub(crate) serialize: fn(&ArcAny, &mut dyn std::io::Write) -> Result<()>,
65    pub(crate) deserialize: fn(&Bytes) -> Result<ArcAny>,
66}
67
68impl std::fmt::Debug for CacheCodec {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        f.debug_struct("CacheCodec").finish_non_exhaustive()
71    }
72}
73
74fn serialize_via_impl<T: CacheCodecImpl + 'static>(
75    any: &ArcAny,
76    writer: &mut dyn std::io::Write,
77) -> Result<()> {
78    let val = any
79        .downcast_ref::<T>()
80        .expect("CacheCodec::serialize called with wrong type (this is a bug in the cache layer)");
81    val.serialize(writer)
82}
83
84fn deserialize_via_impl<T: CacheCodecImpl + 'static>(data: &Bytes) -> Result<ArcAny> {
85    let val = T::deserialize(data)?;
86    Ok(Arc::new(val) as ArcAny)
87}
88
89impl CacheCodec {
90    /// Create a `CacheCodec` from plain function pointers.
91    ///
92    /// Prefer [`from_impl`](Self::from_impl) when the value type implements
93    /// [`CacheCodecImpl`]. Use this for types where a direct impl isn't
94    /// possible (e.g. orphan rule prevents it).
95    pub fn new(
96        serialize: fn(&ArcAny, &mut dyn std::io::Write) -> Result<()>,
97        deserialize: fn(&Bytes) -> Result<ArcAny>,
98    ) -> Self {
99        Self {
100            serialize,
101            deserialize,
102        }
103    }
104
105    /// Create a `CacheCodec` from a [`CacheCodecImpl`] implementation.
106    ///
107    /// For **sized** types stored directly in the cache. The codec
108    /// downcasts `&dyn Any` to `&T` for serialization and returns `Arc<T>`
109    /// from deserialization.
110    pub fn from_impl<T: CacheCodecImpl + 'static>() -> Self {
111        Self {
112            serialize: serialize_via_impl::<T>,
113            deserialize: deserialize_via_impl::<T>,
114        }
115    }
116
117    pub fn serialize(&self, value: &ArcAny, writer: &mut dyn std::io::Write) -> Result<()> {
118        (self.serialize)(value, writer)
119    }
120
121    pub fn deserialize(&self, data: &Bytes) -> Result<ArcAny> {
122        (self.deserialize)(data)
123    }
124}