use std::ops::Deref;
use crate::{Surrogate, Surrogated};
impl Surrogated for () {
type Surrogate = ();
fn into_surrogate(self) -> Self::Surrogate {}
}
impl Surrogate for () {
type Real = ();
fn into_real(self) -> Self::Real {}
}
pub trait TupleProject<'a> {
type Projected;
fn project(&'a self) -> Self::Projected;
}
pub struct TupleRefSurrogate<'a, T>
where
T: TupleProject<'a>,
{
real: &'a T,
projected: T::Projected,
}
impl<'a, T> TupleRefSurrogate<'a, T>
where
T: TupleProject<'a>,
{
fn new(real: &'a T) -> Self {
Self {
real,
projected: real.project(),
}
}
}
impl<'a, T> TupleRefSurrogate<'a, T>
where
T: TupleProject<'a> + Surrogated + Clone,
{
#[must_use]
#[allow(clippy::should_implement_trait)]
pub fn clone(&self) -> T::Surrogate {
self.real.clone().into_surrogate()
}
}
impl<'a, T> Deref for TupleRefSurrogate<'a, T>
where
T: TupleProject<'a>,
{
type Target = T::Projected;
fn deref(&self) -> &Self::Target {
&self.projected
}
}
impl<'a, T> serde::Serialize for TupleRefSurrogate<'a, T>
where
T: TupleProject<'a>,
T::Projected: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.projected.serialize(serializer)
}
}
macro_rules! impl_tuple_surrogate {
($($t:ident $idx:tt),+ $(,)?) => {
impl<$($t),+> Surrogated for ($($t,)+)
where
$($t: Surrogated,)+
{
type Surrogate = ($(<$t as Surrogated>::Surrogate,)+);
fn into_surrogate(self) -> Self::Surrogate {
($(self.$idx.into_surrogate(),)+)
}
}
impl<$($t),+> Surrogate for ($($t,)+)
where
$($t: Surrogate,)+
{
type Real = ($(<$t as Surrogate>::Real,)+);
fn into_real(self) -> Self::Real {
($(self.$idx.into_real(),)+)
}
}
impl<'a, $($t: 'a),+> TupleProject<'a> for ($($t,)+)
where
$(&'a $t: Surrogated,)+
{
type Projected = ($(<&'a $t as Surrogated>::Surrogate,)+);
fn project(&'a self) -> Self::Projected {
($((&self.$idx).into_surrogate(),)+)
}
}
impl<'a, $($t: 'a),+> Surrogated for &'a ($($t,)+)
where
$(&'a $t: Surrogated,)+
{
type Surrogate = TupleRefSurrogate<'a, ($($t,)+)>;
fn into_surrogate(self) -> Self::Surrogate {
TupleRefSurrogate::new(self)
}
}
impl<'a, $($t: 'a),+> Surrogate for TupleRefSurrogate<'a, ($($t,)+)>
where
$(&'a $t: Surrogated,)+
{
type Real = &'a ($($t,)+);
fn into_real(self) -> Self::Real {
self.real
}
}
};
}
impl_tuple_surrogate!(T1 0);
impl_tuple_surrogate!(T1 0, T2 1);
impl_tuple_surrogate!(T1 0, T2 1, T3 2);
impl_tuple_surrogate!(T1 0, T2 1, T3 2, T4 3);
impl_tuple_surrogate!(T1 0, T2 1, T3 2, T4 3, T5 4);
impl_tuple_surrogate!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5);
impl_tuple_surrogate!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6);
impl_tuple_surrogate!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7);
impl_tuple_surrogate!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7, T9 8);
impl_tuple_surrogate!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7, T9 8, T10 9);
impl_tuple_surrogate!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7, T9 8, T10 9, T11 10);
impl_tuple_surrogate!(
T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7, T9 8, T10 9, T11 10, T12 11,
);