use crate::prelude::*;
use crate::col::{Col, ColProxy};
use crate::header::{Header, HasCol, AsListRefs};
pub mod proj;
pub mod tuple;
pub mod rename;
pub trait Record:Sized + Clone {
type Cols: Header;
fn into_cols(self)->Self::Cols {
self.clone_cols()
}
fn clone_cols(&self)->Self::Cols {
Self::Cols::clone_from_rec_unchecked(self)
}
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> {
self.col_opt::<C>().unwrap()
}
fn col_opt<C:Col>(&self)->Option<&C>;
fn project<NewCols:Header>(self) -> proj::Projection<Self, NewCols>
where NewCols: ProjectFrom<Self::Cols> {
proj::Projection::new(self)
}
fn project_into<R:FromRecord<Self::Cols>>(self)->R {
R::from_rec(self).0
}
fn rename_col<A:Col, B:Col<Inner=A>>(self)->rename::Rename<Self,A,B>
where rename::Rename<Self,A,B>: Record {
rename::Rename { inner: self, cols: std::marker::PhantomData }
}
}
pub struct ErasedExtRecord<'a,Cols: Header>(
<Cols as AsListRefs<'a>>::AsRefs
);
impl<'a, H:Header> Copy for ErasedExtRecord<'a,H> {}
impl<'a, H:Header> Clone for ErasedExtRecord<'a,H> {
fn clone(&self)->Self { *self }
}
impl<'a,Cols:Header> Record for ErasedExtRecord<'a,Cols>
where <Cols as AsListRefs<'a>>::AsRefs: ExternalRecord<'a, Cols=Cols> {
type Cols = Cols;
fn into_cols(self)->Self::Cols { self.0.into_cols() }
fn clone_cols(&self)->Self::Cols { self.0.clone_cols() }
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> { self.0.col_ref() }
fn col_opt<C:Col>(&self)->Option<&C> { self.0.col_opt() }
}
impl<'a,Cols:Header> ExternalRecord<'a> for ErasedExtRecord<'a,Cols>
where <Cols as AsListRefs<'a>>::AsRefs: ExternalRecord<'a, Cols=Cols> {
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> {
self.0.ext_col_ref()
}
fn ext_col_opt<C:Col>(&self)->Option<&'a C> {
self.0.ext_col_opt()
}
}
impl<'a,Cols:Header> FromExternalRecord<'a> for ErasedExtRecord<'a,Cols>
{
type Cols = Cols;
fn from_ext_rec_raw(r:impl ExternalRecord<'a, Cols=Cols>)->Self {
ErasedExtRecord(
Cols::ref_from_ext_rec_unchecked(r)
)
}
}
pub trait ExternalRecord<'a>: Record + Copy {
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> {
self.ext_col_opt::<C>().unwrap()
}
fn ext_col_opt<C:Col>(&self)->Option<&'a C>;
fn erase_type(self)->ErasedExtRecord<'a, Self::Cols> {
ErasedExtRecord::from_ext_rec_raw(self)
}
}
impl<'a, R:Record> ExternalRecord<'a> for &'a R {
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> {
<R as Record>::col_ref(self)
}
fn ext_col_opt<C:Col>(&self)->Option<&'a C> {
<R as Record>::col_opt(self)
}
}
impl<'a> ExternalRecord<'a> for HNil {
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> {
unreachable!();
}
fn ext_col_opt<C:Col>(&self)->Option<&'a C> {
None
}
}
impl<'a,R> ExternalRecord<'a> for OpaqueRecord<R>
where R:ExternalRecord<'a> {
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> {
self.0.ext_col_ref()
}
fn ext_col_opt<C:Col>(&self)->Option<&'a C> {
self.0.ext_col_opt()
}
}
impl<'a,H,T> ExternalRecord<'a> for HCons<&'a H, T>
where
H: Col,
T: ExternalRecord<'a>,
Self: Record
{
fn ext_col_ref<C:Col>(&self)->&'a C where Self::Cols: HasCol<C> {
self.ext_col_opt().unwrap()
}
fn ext_col_opt<C:Col>(&self)->Option<&'a C> {
if std::any::TypeId::of::<C>() == std::any::TypeId::of::<H>() {
Some(unsafe { &*(self.head as *const H as *const C) })
} else {
self.tail.ext_col_opt()
}
}
}
#[derive(Copy,Clone,Default,Eq,PartialEq,Ord,PartialOrd,Hash)]
#[repr(transparent)]
pub struct OpaqueRecord<R>(R);
impl<R> OpaqueRecord<R> {
pub fn new(r:R)->Self { OpaqueRecord(r) }
}
impl<R:Record> Record for OpaqueRecord<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 Record for HNil {
type Cols = HNil;
#[inline(always)]
fn into_cols(self)->HNil { HNil }
#[inline(always)]
fn clone_cols(&self)->HNil { HNil }
#[inline(always)]
fn col_ref<C:Col>(&self)->&C
{ unreachable!() }
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C>
{ None }
}
impl<H:ColProxy, T:Record> Record for HCons<H,T>
where HCons<H::For, T::Cols>: Header, Self:Clone
{
type Cols = HCons<H::For, T::Cols>;
#[inline(always)]
fn into_cols(self)->Self::Cols {
HCons { head: self.head.into_col(),
tail: self.tail.into_cols() }
}
#[inline(always)]
fn clone_cols(&self)->Self::Cols {
HCons { head: self.head.col_ref().clone(),
tail: self.tail.clone_cols() }
}
#[inline(always)]
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> {
self.col_opt().unwrap_or_else(|| unreachable!())
}
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C> {
(self.head.col_ref() as &dyn ::core::any::Any)
.downcast_ref()
.or_else(|| self.tail.col_opt())
}
}
pub trait BorrowRecord {
type Cols: Header;
type Inner: Record<Cols=Self::Cols> + ?Sized;
fn borrow_rec(&self) -> &Self::Inner;
}
impl<R:Record + ?Sized> BorrowRecord for R {
type Cols = R::Cols;
type Inner = R;
#[inline(always)]
fn borrow_rec(&self)->&Self::Inner { self }
}
impl<'a, Ptr:BorrowRecord+?Sized> Record for &'a Ptr {
type Cols = Ptr::Cols;
#[inline(always)]
fn into_cols(self)->Self::Cols {
Ptr::Inner::clone_cols(Ptr::borrow_rec(self))
}
#[inline(always)]
fn clone_cols(&self)->Self::Cols {
Ptr::Inner::clone_cols(Ptr::borrow_rec(*self))
}
#[inline(always)]
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> {
Ptr::Inner::col_ref(Ptr::borrow_rec(*self))
}
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C> {
Ptr::Inner::col_opt(Ptr::borrow_rec(*self))
}
}
impl<Ptr: BorrowRecord+?Sized> Record for std::rc::Rc<Ptr> {
type Cols = Ptr::Cols;
#[inline(always)]
fn into_cols(self)->Self::Cols {
Ptr::Inner::clone_cols(Ptr::borrow_rec(&self))
}
#[inline(always)]
fn clone_cols(&self)->Self::Cols {
Ptr::Inner::clone_cols(Ptr::borrow_rec(&*self))
}
#[inline(always)]
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> {
Ptr::Inner::col_ref(Ptr::borrow_rec(&*self))
}
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C> {
Ptr::Inner::col_opt(Ptr::borrow_rec(&*self))
}
}
impl<Ptr: BorrowRecord+?Sized> Record for std::sync::Arc<Ptr> {
type Cols = Ptr::Cols;
#[inline(always)]
fn into_cols(self)->Self::Cols {
Ptr::Inner::clone_cols(Ptr::borrow_rec(&self))
}
#[inline(always)]
fn clone_cols(&self)->Self::Cols {
Ptr::Inner::clone_cols(Ptr::borrow_rec(&*self))
}
#[inline(always)]
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> {
Ptr::Inner::col_ref(Ptr::borrow_rec(&*self))
}
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C> {
Ptr::Inner::col_opt(Ptr::borrow_rec(&*self))
}
}
impl<Ptr: BorrowRecord+Clone> Record for std::boxed::Box<Ptr> {
type Cols = Ptr::Cols;
#[inline(always)]
fn into_cols(self)->Self::Cols {
Ptr::Inner::clone_cols(Ptr::borrow_rec(&self))
}
#[inline(always)]
fn clone_cols(&self)->Self::Cols {
Ptr::Inner::clone_cols(Ptr::borrow_rec(&*self))
}
#[inline(always)]
fn col_ref<C:Col>(&self)->&C where Self::Cols: HasCol<C> {
Ptr::Inner::col_ref(Ptr::borrow_rec(&*self))
}
#[inline(always)]
fn col_opt<C:Col>(&self)->Option<&C> {
Ptr::Inner::col_opt(Ptr::borrow_rec(&*self))
}
}
impl<H,T> FromRecordImpl for HCons<H,T> where Self:Header {
type Cols = Self;
fn from_rec_raw(rec: impl Record<Cols=Self::Cols>)->Self {
rec.into_cols()
}
}
pub trait FromRecordImpl: Sized {
type Cols: Header;
fn from_rec_raw(rec: impl Record<Cols=Self::Cols>)->Self;
}
pub trait FromRecord<SrcCols:Header>: Sized {
type Remainder: Header;
fn from_rec(rec: impl Record<Cols=SrcCols>)->(Self, Self::Remainder);
}
pub trait FromRecordUnchecked<'a>: Sized {
fn from_ref_unchecked(_:&impl ExternalRecord<'a>)->Self;
}
impl<'a> FromRecordUnchecked<'a> for HNil {
fn from_ref_unchecked(_:&impl ExternalRecord<'a>)->Self { HNil }
}
impl<'a,H:Col,T:FromRecordUnchecked<'a>>
FromRecordUnchecked<'a> for HCons<&'a H,T> {
fn from_ref_unchecked(r:&impl ExternalRecord<'a>)->Self {
HCons { head: r.ext_col_opt::<H>().unwrap(),
tail: T::from_ref_unchecked(r) }
}
}
pub trait FromExternalRecord<'a>: Sized {
type Cols: Header;
fn from_ext_rec_raw(rec: impl ExternalRecord<'a, Cols=Self::Cols>)->Self;
fn from_ext_rec<H>(rec: impl ExternalRecord<'a, Cols=H>)->Self
where H:Header, Self::Cols: ProjectFrom<H> {
Self::from_ext_rec_raw(rec.project())
}
}
impl<'a> FromExternalRecord<'a> for HNil {
type Cols = HNil;
fn from_ext_rec_raw(_: impl ExternalRecord<'a, Cols=Self::Cols>)->Self {
HNil
}
}
impl<'a,H,T> FromExternalRecord<'a> for HCons<H, T>
where H:FromExternalRecord<'a>,
H: ColProxy,
T:FromExternalRecord<'a>,
HCons<H::For,T::Cols>: Header {
type Cols = HCons<H::For,T::Cols>;
fn from_ext_rec_raw(rec: impl ExternalRecord<'a, Cols=Self::Cols>)->Self {
HCons {
head: H::from_ext_rec_raw(proj::Projection::new_unchecked(rec)),
tail: T::from_ext_rec_raw(proj::Projection::new_unchecked(rec))
}
}
}
use crate::header::{ProjectFrom, ProjectRefFrom};
impl<T:FromRecordImpl, SrcCols:Header> FromRecord<SrcCols> for T
where T::Cols: ProjectFrom<SrcCols> + Record<Cols=T::Cols>
{
type Remainder = <T::Cols as ProjectFrom<SrcCols>>::Remainder;
#[inline(always)]
fn from_rec(rec: impl Record<Cols=SrcCols>)->(Self, Self::Remainder) {
let (cols, remainder) = T::Cols::project_from(rec.into_cols());
(Self::from_rec_raw(cols), remainder)
}
}
#[test]
fn test() {
col!{pub A: u32};
col!{pub B: &'static str};
use tylisp::sexpr;
assert_trait!{ HNil: Record };
assert_trait!{ sexpr!{A}: Record };
assert_trait!{ sexpr!{std::rc::Rc<A>, &B}: Record<Cols=sexpr!{A,B}> };
assert_trait!{ sexpr!{std::rc::Rc<A>}: Record };
assert_trait!{ &sexpr!{std::rc::Rc<A>, &B}: Record<Cols=sexpr!{A,B}> };
fn f(_:impl Record) {}
f(HNil);
}