use std::marker::PhantomData;
use postgres_types::to_sql_checked;
use simple_pg_client::types::ToSql;
trait SqlConversion<T> {
type Output: Sized + ToSql;
fn map(input: &T) -> Self::Output;
}
#[repr(transparent)]
pub struct ToSqlVia<T: Sized, M> {
x: T,
__marker: PhantomData<M>,
}
impl<T: std::fmt::Debug, M> std::fmt::Debug for ToSqlVia<T, M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ToSqlVia").finish()
}
}
impl<T, M> ToSqlVia<T, M> {
pub fn from_ref(x: &T) -> &ToSqlVia<T, M> {
unsafe { std::mem::transmute(x) }
}
}
impl<T, X: ToSql, F: Fn(&T) -> X> SqlConversion<T> for F {
type Output = X;
fn map(input: &T) -> Self::Output {
assert_eq!(std::mem::size_of::<F>(), 0);
let func: Self = unsafe { std::mem::transmute_copy::<(), Self>(&()) };
(func)(input)
}
}
pub fn lazy_binding<T, X, F: Fn(&T) -> X>(x: &T, _f: F) -> &ToSqlVia<T, F> {
assert_eq!(
std::mem::size_of::<F>(),
0,
"Function must not capture anything."
);
ToSqlVia::from_ref(x)
}
impl<T, M> ToSql for ToSqlVia<T, M>
where
T: std::fmt::Debug,
M: SqlConversion<T>,
{
fn to_sql(
&self,
ty: &postgres_types::Type,
out: &mut bytes::BytesMut,
) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>>
where
Self: Sized,
{
(M::map(&self.x)).to_sql(ty, out)
}
fn accepts(ty: &postgres_types::Type) -> bool
where
Self: Sized,
{
<M::Output>::accepts(ty)
}
to_sql_checked! {}
}
#[derive(Debug)]
pub struct IgnoreType<T>(pub T);
impl<T> ToSql for IgnoreType<T>
where
T: std::fmt::Debug + ToSql,
{
fn to_sql(
&self,
ty: &postgres_types::Type,
out: &mut bytes::BytesMut,
) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>>
where
Self: Sized,
{
self.0.to_sql(ty, out)
}
fn accepts(_ty: &postgres_types::Type) -> bool
where
Self: Sized,
{
true
}
fn to_sql_checked(
&self,
ty: &postgres_types::Type,
out: &mut bytes::BytesMut,
) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> {
self.0.to_sql(ty, out)
}
}