evento_sql/
sql_types.rs

1//! SQL type wrappers for serialization.
2//!
3//! This module provides the [`Rkyv`] wrapper type for zero-copy serialization
4//! of Rust types to/from SQL BLOB columns using the rkyv format.
5
6use std::ops::{Deref, DerefMut};
7
8use sqlx::database::Database;
9use sqlx::decode::Decode;
10use sqlx::encode::{Encode, IsNull};
11use sqlx::error::BoxDynError;
12use sqlx::sqlite::{SqliteArgumentValue, SqliteTypeInfo};
13use sqlx::types::Type;
14
15/// A wrapper type for rkyv-serialized data in SQL databases.
16///
17/// `Rkyv<T>` wraps a value of type `T` and provides automatic serialization/deserialization
18/// using the [rkyv](https://rkyv.org/) zero-copy framework when storing to or reading from
19/// SQL databases.
20///
21/// # Features
22///
23/// - **Zero-copy deserialization** - Data can be accessed directly from the buffer without copying
24/// - **Compact binary format** - Efficient storage compared to JSON or other text formats
25/// - **Type-safe** - Compile-time checking of serialization capabilities
26///
27/// # Database Support
28///
29/// Currently implements SQLx traits for SQLite. Data is stored as BLOB.
30///
31/// # Example
32///
33/// ```rust,ignore
34/// use evento_sql::sql_types::Rkyv;
35/// use rkyv::{Archive, Serialize, Deserialize};
36///
37/// #[derive(Archive, Serialize, Deserialize)]
38/// struct MyData {
39///     value: i32,
40///     name: String,
41/// }
42///
43/// // Wrap data for storage
44/// let data = Rkyv(MyData { value: 42, name: "test".into() });
45///
46/// // Encode to bytes
47/// let bytes = data.encode_to()?;
48///
49/// // Decode from bytes
50/// let decoded = Rkyv::<MyData>::decode_from_bytes(&bytes)?;
51/// assert_eq!(decoded.value, 42);
52/// ```
53///
54/// # Deref
55///
56/// `Rkyv<T>` implements `Deref` and `DerefMut` to `T`, allowing transparent access
57/// to the inner value.
58#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
59pub struct Rkyv<T: ?Sized>(pub T);
60
61impl<T> From<T> for Rkyv<T> {
62    fn from(value: T) -> Self {
63        Self(value)
64    }
65}
66
67impl<T> Deref for Rkyv<T> {
68    type Target = T;
69
70    fn deref(&self) -> &Self::Target {
71        &self.0
72    }
73}
74
75impl<T> DerefMut for Rkyv<T> {
76    fn deref_mut(&mut self) -> &mut Self::Target {
77        &mut self.0
78    }
79}
80
81impl<T> AsRef<T> for Rkyv<T> {
82    fn as_ref(&self) -> &T {
83        &self.0
84    }
85}
86
87impl<T> AsMut<T> for Rkyv<T> {
88    fn as_mut(&mut self) -> &mut T {
89        &mut self.0
90    }
91}
92
93impl<T> Rkyv<T>
94where
95    T: for<'a> rkyv::Serialize<
96        rkyv::rancor::Strategy<
97            rkyv::ser::Serializer<
98                rkyv::util::AlignedVec,
99                rkyv::ser::allocator::ArenaHandle<'a>,
100                rkyv::ser::sharing::Share,
101            >,
102            rkyv::rancor::Error,
103        >,
104    >,
105{
106    /// Serializes the wrapped value to a byte vector using rkyv.
107    ///
108    /// # Errors
109    ///
110    /// Returns an error if serialization fails.
111    pub fn encode_to(&self) -> Result<Vec<u8>, rkyv::rancor::Error> {
112        let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&self.0)?;
113        Ok(bytes.to_vec())
114    }
115}
116
117impl<T> Rkyv<T>
118where
119    T: rkyv::Archive,
120    <T as rkyv::Archive>::Archived: for<'a> rkyv::bytecheck::CheckBytes<
121            rkyv::rancor::Strategy<
122                rkyv::validation::Validator<
123                    rkyv::validation::archive::ArchiveValidator<'a>,
124                    rkyv::validation::shared::SharedValidator,
125                >,
126                rkyv::rancor::Error,
127            >,
128        > + rkyv::Deserialize<T, rkyv::rancor::Strategy<rkyv::de::Pool, rkyv::rancor::Error>>,
129{
130    /// Deserializes a value from a byte slice using rkyv.
131    ///
132    /// # Errors
133    ///
134    /// Returns an error if deserialization fails or the data is invalid.
135    pub fn decode_from_bytes(bytes: &[u8]) -> Result<Self, rkyv::rancor::Error> {
136        let data = rkyv::from_bytes::<T, rkyv::rancor::Error>(bytes)?;
137        Ok(Self(data))
138    }
139}
140
141impl<T> Type<sqlx::Sqlite> for Rkyv<T> {
142    fn type_info() -> SqliteTypeInfo {
143        <&[u8] as Type<sqlx::Sqlite>>::type_info()
144    }
145
146    fn compatible(ty: &SqliteTypeInfo) -> bool {
147        <&[u8] as Type<sqlx::Sqlite>>::compatible(ty)
148    }
149}
150
151impl<T> Encode<'_, sqlx::Sqlite> for Rkyv<T>
152where
153    T: for<'a> rkyv::Serialize<
154        rkyv::rancor::Strategy<
155            rkyv::ser::Serializer<
156                rkyv::util::AlignedVec,
157                rkyv::ser::allocator::ArenaHandle<'a>,
158                rkyv::ser::sharing::Share,
159            >,
160            rkyv::rancor::Error,
161        >,
162    >,
163{
164    fn encode_by_ref(
165        &self,
166        buf: &mut <sqlx::Sqlite as Database>::ArgumentBuffer<'_>,
167    ) -> Result<IsNull, BoxDynError> {
168        let data = self.encode_to()?;
169        buf.push(SqliteArgumentValue::Blob(std::borrow::Cow::Owned(data)));
170
171        Ok(IsNull::No)
172    }
173}
174
175impl<'r, T> Decode<'r, sqlx::Sqlite> for Rkyv<T>
176where
177    T: rkyv::Archive,
178    <T as rkyv::Archive>::Archived: for<'a> rkyv::bytecheck::CheckBytes<
179            rkyv::rancor::Strategy<
180                rkyv::validation::Validator<
181                    rkyv::validation::archive::ArchiveValidator<'a>,
182                    rkyv::validation::shared::SharedValidator,
183                >,
184                rkyv::rancor::Error,
185            >,
186        > + rkyv::Deserialize<T, rkyv::rancor::Strategy<rkyv::de::Pool, rkyv::rancor::Error>>,
187    Vec<u8>: sqlx::Decode<'r, sqlx::Sqlite>,
188{
189    fn decode(value: <sqlx::Sqlite as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
190        let decoded = Vec::<u8>::decode(value)?;
191        let data = Rkyv::<T>::decode_from_bytes(&decoded[..])?;
192
193        Ok(data)
194    }
195}