use {
crate::{
record::{
Record,
FromRecord,
FromRecordImpl,
ExternalRecord,
FromExternalRecord,
proj
},
header::{Header, HasCol},
col::Col,
},
tylisp::{
HNil,
sexpr, calc, calc_ty,
engine::{Eval, Calc},
ops::list::{Concat,Union},
},
};
impl Record for () {
type Cols = HNil;
#[inline(always)]
fn into_cols(self)->Self::Cols { HNil }
#[inline(always)]
fn clone_cols(&self)->Self::Cols { HNil }
#[inline(always)]
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> { unreachable!() }
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C> { None }
}
impl<'a> ExternalRecord<'a> for () {
#[inline(always)]
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> { unreachable!() }
#[inline(always)]
fn ext_col_opt<C:Col>(&self)->Option<&'a C> { None }
}
impl FromRecordImpl for () {
type Cols = HNil;
fn from_rec_raw(_: impl Record<Cols=Self::Cols>)->Self { () }
}
impl<'a> FromExternalRecord<'a> for () {
type Cols = HNil;
fn from_ext_rec_raw(_: impl ExternalRecord<'a, Cols=Self::Cols>)->Self { () }
}
impl<R:Record> Record for (R,) {
type Cols = R::Cols;
#[inline(always)]
fn into_cols(self)->Self::Cols { self.0.into_cols() }
#[inline(always)]
fn clone_cols(&self)->Self::Cols { self.0.clone_cols() }
#[inline(always)]
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> { self.0.col_ref() }
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C> { self.0.col_opt() }
}
impl<'a,R> ExternalRecord<'a> for (R,)
where R: ExternalRecord<'a> {
#[inline(always)]
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> { self.0.ext_col_ref() }
#[inline(always)]
fn ext_col_opt<C:Col>(&self)->Option<&'a C> { self.0.ext_col_opt() }
}
impl<R:FromRecordImpl> FromRecordImpl for (R,) {
type Cols = R::Cols;
fn from_rec_raw(r: impl Record<Cols=Self::Cols>)->Self { (R::from_rec_raw(r),) }
}
impl<'a, R:FromExternalRecord<'a>> FromExternalRecord<'a> for (R,) {
type Cols = R::Cols;
fn from_ext_rec_raw(r: impl ExternalRecord<'a, Cols=Self::Cols>)->Self {
(R::from_ext_rec_raw(r),)
}
}
impl<A:Record, B:Record> Record for (A,B)
where sexpr!{Concat, @A::Cols = a, @B::Cols = b}: Calc<sexpr!{(), A::Cols, B::Cols}>,
calc_ty!{Concat, @A::Cols = a, @B::Cols = b}: Header
{
type Cols = calc_ty!{Concat, @A::Cols = a, @B::Cols = b};
#[inline(always)]
fn into_cols(self)->Self::Cols {
calc!{Concat, @A::Cols = self.0.into_cols(),
@B::Cols = self.1.into_cols()}
}
#[inline(always)]
fn clone_cols(&self)->Self::Cols {
calc!{Concat, @A::Cols = self.0.clone_cols(),
@B::Cols = self.1.clone_cols()}
}
#[inline(always)]
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> {
match (self.0.col_opt(), self.1.col_opt()) {
(Some(x), None) => x,
(None, Some(x)) => x,
_ => unreachable!()
}
}
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C> {
match (self.0.col_opt(), self.1.col_opt()) {
(Some(x), None) => Some(x),
(None, Some(x)) => Some(x),
(None, None) => None,
_ => unreachable!()
}
}
}
impl<'a,A,B> ExternalRecord<'a> for (A,B)
where Self: Record, A:ExternalRecord<'a>, B:ExternalRecord<'a> {
#[inline(always)]
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> {
match (self.0.ext_col_opt(), self.1.ext_col_opt()) {
(Some(x), None) => x,
(None, Some(x)) => x,
_ => unreachable!()
}
}
#[inline(always)]
fn ext_col_opt<C:Col>(&self)->Option<&'a C> {
match (self.0.ext_col_opt(), self.1.ext_col_opt()) {
(Some(x), None) => Some(x),
(None, Some(x)) => Some(x),
_ => None
}
}
}
impl<A:FromRecordImpl, B:FromRecordImpl, H:Header> FromRecordImpl for (A,B)
where sexpr!{Concat, @A::Cols, @B::Cols}: Eval<Result = H>,
A: FromRecord<H, Remainder = B::Cols>,
B::Cols: Record<Cols = B::Cols>,
{
type Cols = H;
fn from_rec_raw(r: impl Record<Cols=Self::Cols>)->Self {
let (a, remainder) = A::from_rec(r);
let b = B::from_rec_raw(remainder);
(a,b)
}
}
impl<'a,A,B,H> FromExternalRecord<'a> for (A,B)
where A: FromExternalRecord<'a>,
B: FromExternalRecord<'a>,
sexpr!{Union, @A::Cols, @B::Cols}: Eval<Result = H>,
H: Header,
{
type Cols = H;
fn from_ext_rec_raw(r: impl ExternalRecord<'a, Cols=H>)->Self {
(
A::from_ext_rec_raw(proj::Projection::new_unchecked(r)),
B::from_ext_rec_raw(proj::Projection::new_unchecked(r)),
)
}
}
impl<A,B,C,HH:Header> Record for (A,B,C)
where
A: Record,
B: Record,
C: Record,
(A, (B,C)): Record<Cols=HH>
{
type Cols = HH;
fn into_cols(self)->HH {
let (a,b,c) = self;
(a,(b,c)).into_cols()
}
fn col_opt<CC:Col>(&self)->Option<&CC> {
let &(ref a, ref b, ref c) = self;
None
.or(a.col_opt())
.or(b.col_opt())
.or(c.col_opt())
}
}
impl<'a,A,B,C> ExternalRecord<'a> for (A,B,C)
where Self: Record,
A:ExternalRecord<'a>,
B:ExternalRecord<'a>,
C:ExternalRecord<'a>,
{
fn ext_col_opt<CC:Col>(&self)->Option<&'a CC> {
let &(ref a, ref b, ref c) = self;
None
.or(a.ext_col_opt())
.or(b.ext_col_opt())
.or(c.ext_col_opt())
}
}
impl<A, B, C, H:Header> FromRecordImpl for (A,B,C)
where (A,(B,C)): FromRecordImpl<Cols=H>
{
type Cols = H;
fn from_rec_raw(r: impl Record<Cols=Self::Cols>)->Self {
let (a, (b,c)) = FromRecordImpl::from_rec_raw(r);
(a,b,c)
}
}
impl<'a,A,B,C,HH:Header> FromExternalRecord<'a> for (A,B,C)
where (A,(B,C)): FromExternalRecord<'a, Cols=HH>
{
type Cols = HH;
fn from_ext_rec_raw(r: impl ExternalRecord<'a, Cols=HH>)->Self {
let (a, (b,c)) = FromExternalRecord::from_ext_rec_raw(r);
(a,b,c)
}
}
#[test]
fn test_tuple_records() {
col!{pub A: u32};
col!{pub B: u32};
col!{pub C: u32};
col!{pub D: u32};
assert_trait!{ (): Record<Cols=sexpr!{}> };
assert_trait!{ (A,): Record<Cols=sexpr!{A}> };
assert_trait!{ (A, B): Record<Cols=sexpr!{A,B}> };
assert_trait!{ (A, (B,C)): Record<Cols=sexpr!{A,B,C}> };
assert_trait!{ (A, B, C): Record<Cols=sexpr!{A,B,C}> };
assert_trait!{ (std::sync::Arc<(A,D)>, (B,C)): Record<Cols=sexpr!{A,D,B,C}> };
assert_trait!{ (A, &(B,C)): Record<Cols=sexpr!{A,B,C}> };
use tylisp::sexpr_val;
assert_eq!( ( ((A(1), B(2)), C(3) ), sexpr_val!{D(4)}),
<((A,B),C) as FromRecord<_>>::from_rec(sexpr_val!{B(2),C(3),D(4),A(1)}) );
}