use std::ops::{Deref, DerefMut};
use sqlx::database::Database;
use sqlx::decode::Decode;
use sqlx::encode::{Encode, IsNull};
use sqlx::error::BoxDynError;
use sqlx::sqlite::{SqliteArgumentValue, SqliteTypeInfo};
use sqlx::types::Type;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Bitcode<T: ?Sized>(pub T);
impl<T> From<T> for Bitcode<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl<T> Deref for Bitcode<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Bitcode<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> AsRef<T> for Bitcode<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> AsMut<T> for Bitcode<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T> Bitcode<T>
where
T: bitcode::Encode,
{
pub fn encode_to(&self) -> Vec<u8> {
bitcode::encode(&self.0)
}
}
impl<T> Bitcode<T>
where
T: bitcode::DecodeOwned,
{
pub fn decode_from_bytes(bytes: &[u8]) -> Result<Self, bitcode::Error> {
let data = bitcode::decode::<T>(bytes)?;
Ok(Self(data))
}
}
impl<T> Type<sqlx::Sqlite> for Bitcode<T> {
fn type_info() -> SqliteTypeInfo {
<&[u8] as Type<sqlx::Sqlite>>::type_info()
}
fn compatible(ty: &SqliteTypeInfo) -> bool {
<&[u8] as Type<sqlx::Sqlite>>::compatible(ty)
}
}
impl<T> Encode<'_, sqlx::Sqlite> for Bitcode<T>
where
T: bitcode::Encode,
{
fn encode_by_ref(
&self,
buf: &mut <sqlx::Sqlite as Database>::ArgumentBuffer<'_>,
) -> Result<IsNull, BoxDynError> {
buf.push(SqliteArgumentValue::Blob(std::borrow::Cow::Owned(
self.encode_to(),
)));
Ok(IsNull::No)
}
}
impl<'r, T> Decode<'r, sqlx::Sqlite> for Bitcode<T>
where
T: bitcode::DecodeOwned,
Vec<u8>: sqlx::Decode<'r, sqlx::Sqlite>,
{
fn decode(value: <sqlx::Sqlite as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
let decoded = Vec::<u8>::decode(value)?;
let data = Bitcode::<T>::decode_from_bytes(&decoded[..])?;
Ok(data)
}
}