use std::collections::VecDeque;
use std::marker::PhantomData;
use std::ops::{Add, BitAnd, BitOr, Not, Sub};
use typenum::{
bit::{B0, B1},
marker_traits::Bit,
operator_aliases::{Add1, And, Or, Sub1},
type_operators::IsEqual,
uint::{UInt, UTerm, Unsigned},
};
use access::NRows;
use cons::{cons, Cons, Nil};
use store::DataRef;
pub trait Identifier {
type Ident: Identifier;
type Table;
type Natural;
}
pub trait Label: Identifier {
const NAME: &'static str;
const TYPE: &'static str;
}
#[derive(Debug, Clone)]
pub struct Ident<Tbl, Nat> {
_marker: PhantomData<(Tbl, Nat)>,
}
impl<Tbl, Nat> Identifier for Ident<Tbl, Nat> {
type Ident = Self;
type Table = Tbl;
type Natural = Nat;
}
pub type TblOf<T> = <T as Identifier>::Table;
pub type NatOf<T> = <T as Identifier>::Natural;
impl Identifier for UTerm {
type Ident = Ident<Self::Table, Self::Natural>;
type Table = Local;
type Natural = Self;
}
impl<U, B> Identifier for UInt<U, B> {
type Ident = Ident<Self::Table, Self::Natural>;
type Table = Local;
type Natural = Self;
}
pub trait LabelName {
fn name() -> &'static str;
fn str_type() -> &'static str;
}
impl<T> LabelName for T
where
T: Label,
{
fn name() -> &'static str {
T::NAME
}
fn str_type() -> &'static str {
T::TYPE
}
}
pub trait IdentEq<Other> {
type Eq: Bit;
}
pub type True = B1;
pub type False = B0;
impl<T, U> IdentEq<U> for T
where
T: IsEqual<U>,
{
type Eq = <T as IsEqual<U>>::Output;
}
impl<TTable, TNat, UTbl, UNat> IdentEq<Ident<UTbl, UNat>> for Ident<TTable, TNat>
where
TTable: IsEqual<UTbl>,
TNat: IsEqual<UNat>,
<TTable as IsEqual<UTbl>>::Output: BitAnd<<TNat as IsEqual<UNat>>::Output>,
<<TTable as IsEqual<UTbl>>::Output as BitAnd<<TNat as IsEqual<UNat>>::Output>>::Output: Bit,
{
type Eq = And<<TTable as IsEqual<UTbl>>::Output, <TNat as IsEqual<UNat>>::Output>;
}
pub struct Local;
impl IsEqual<Local> for Local {
type Output = True;
fn is_equal(self, _rhs: Local) -> True {
B1
}
}
pub trait LabelEq<U> {
type Eq;
}
impl<T, U> LabelEq<U> for T
where
T: Identifier,
U: Identifier,
T::Ident: IdentEq<U::Ident>,
{
type Eq = <T::Ident as IdentEq<U::Ident>>::Eq;
}
#[derive(Debug, Clone)]
pub struct Labeled<L, V> {
_label: PhantomData<L>,
pub value: V,
}
impl<L, V> From<V> for Labeled<L, V> {
fn from(orig: V) -> Labeled<L, V> {
Labeled {
_label: PhantomData,
value: orig,
}
}
}
pub trait IntoLabeled: Sized {
fn label<Label>(self) -> Labeled<Label, Self>;
}
impl<T> IntoLabeled for T {
fn label<Label>(self) -> Labeled<Label, T> {
Labeled::from(self)
}
}
#[derive(Debug, Clone)]
pub struct TypedValue<D, V> {
_dtype: PhantomData<D>,
value: V,
}
impl<D, V> From<V> for TypedValue<D, V> {
fn from(orig: V) -> TypedValue<D, V> {
TypedValue {
_dtype: PhantomData,
value: orig,
}
}
}
pub trait Typed {
type DType;
}
impl<D, V> Typed for TypedValue<D, V> {
type DType = D;
}
impl<L, D, V> Typed for Labeled<L, TypedValue<D, V>> {
type DType = D;
}
pub type TypeOf<T> = <T as Typed>::DType;
impl<T> Typed for ::field::FieldData<T> {
type DType = T;
}
impl<T, DI> Typed for ::frame::Framed<T, DI> {
type DType = T;
}
impl<T> Typed for ::store::DataRef<T>
where
T: Typed,
{
type DType = T::DType;
}
pub trait SelfValued {}
macro_rules! impl_selfvalued {
($($dtype:ty)*) => {$(
impl SelfValued for $dtype {}
)*}
}
impl_selfvalued![
f32 f64
i8 i16 i32 i64 i128 isize
u8 u16 u32 u64 u128 usize
bool char str String
];
impl<T> SelfValued for ::field::FieldData<T> {}
impl<T, DI> SelfValued for ::frame::Framed<T, DI> {}
impl<T> SelfValued for DataRef<T> {}
impl<T> SelfValued for PhantomData<T> {}
pub trait Valued {
type Value;
fn value_ref(&self) -> &Self::Value;
fn value_mut(&mut self) -> &mut Self::Value;
fn value(self) -> Self::Value;
}
impl<T> Valued for T
where
T: SelfValued,
{
type Value = Self;
fn value_ref(&self) -> &Self {
self
}
fn value_mut(&mut self) -> &mut Self {
self
}
fn value(self) -> Self::Value {
self
}
}
impl<D, V> Valued for TypedValue<D, V>
where
V: Valued,
{
type Value = V::Value;
fn value_ref(&self) -> &Self::Value {
&self.value.value_ref()
}
fn value_mut(&mut self) -> &mut Self::Value {
self.value.value_mut()
}
fn value(self) -> Self::Value {
self.value.value()
}
}
impl<L, V> Valued for Labeled<L, V>
where
V: Valued,
{
type Value = V::Value;
fn value_ref(&self) -> &V::Value {
self.value.value_ref()
}
fn value_mut(&mut self) -> &mut V::Value {
self.value.value_mut()
}
fn value(self) -> V::Value {
self.value.value()
}
}
pub type ValueOf<T> = <T as Valued>::Value;
pub trait Marked {
type Marker;
}
impl<L, M> Marked for Labeled<L, PhantomData<M>> {
type Marker = M;
}
impl<L, D, M> Marked for Labeled<L, TypedValue<D, PhantomData<M>>> {
type Marker = M;
}
pub type MarkerOf<T> = <T as Marked>::Marker;
pub type LVCons<L, V, T> = Cons<Labeled<L, V>, T>;
pub type LCons<L, T> = LVCons<L, (), T>;
pub type LabelCons<L, T> = LCons<L, T>;
pub type LMCons<L, M, T> = LVCons<L, PhantomData<M>, T>;
pub type LDVCons<L, D, V, T> = LVCons<L, TypedValue<D, V>, T>;
pub trait Member<E> {
type IsMember: Bit;
}
impl<E> Member<E> for Nil {
type IsMember = False;
}
impl<E, L, V, T> Member<E> for LVCons<L, V, T>
where
L: LabelEq<E>,
T: Member<E>,
<L as LabelEq<E>>::Eq: BitOr<<T as Member<E>>::IsMember>,
<<L as LabelEq<E>>::Eq as BitOr<<T as Member<E>>::IsMember>>::Output: Bit,
{
type IsMember = Or<<L as LabelEq<E>>::Eq, <T as Member<E>>::IsMember>;
}
pub trait HasLabels<LabelList> {}
impl<T> HasLabels<Nil> for T {}
impl<NeedleLbl, NeedleValue, NeedleTail, Haystack>
HasLabels<LVCons<NeedleLbl, NeedleValue, NeedleTail>> for Haystack
where
Haystack: Member<NeedleLbl, IsMember = True>,
Haystack: HasLabels<NeedleTail>,
{
}
impl<Needle, Haystack> HasLabels<Needle> for Haystack
where
Needle: Label,
Haystack: Member<Needle, IsMember = True>,
{
}
pub trait IsLabelSet {
type IsSet;
}
impl IsLabelSet for Nil {
type IsSet = True;
}
impl<L, V, T> IsLabelSet for LVCons<L, V, T>
where
T: Member<L>,
<T as Member<L>>::IsMember: Not,
<<T as Member<L>>::IsMember as Not>::Output: BitAnd<<T as IsLabelSet>::IsSet>,
T: IsLabelSet,
{
type IsSet = And<<<T as Member<L>>::IsMember as Not>::Output, <T as IsLabelSet>::IsSet>;
}
pub trait SetDiff<RightSet> {
type Set;
}
impl<LLabel, LValue, LTail> SetDiff<Nil> for LVCons<LLabel, LValue, LTail> {
type Set = LVCons<LLabel, LValue, LTail>;
}
impl<RSet> SetDiff<RSet> for Nil {
type Set = Nil;
}
impl<LLabel, LValue, LTail, RLabel, RValue, RTail> SetDiff<LVCons<RLabel, RValue, RTail>>
for LVCons<LLabel, LValue, LTail>
where
Self: SetDiffStep<LVCons<RLabel, RValue, RTail>, LVCons<RLabel, RValue, RTail>>,
{
type Set =
<Self as SetDiffStep<LVCons<RLabel, RValue, RTail>, LVCons<RLabel, RValue, RTail>>>::Set;
}
pub trait SetDiffStep<RightSet, FullRightSet> {
type Set;
}
impl<RightSet, FullRightSet> SetDiffStep<RightSet, FullRightSet> for Nil {
type Set = Nil;
}
impl<LLabel, LValue, LTail, FullRightSet> SetDiffStep<Nil, FullRightSet>
for LVCons<LLabel, LValue, LTail>
where
LTail: SetDiffStep<FullRightSet, FullRightSet>,
{
type Set = LVCons<LLabel, LValue, <LTail as SetDiffStep<FullRightSet, FullRightSet>>::Set>;
}
impl<LLabel, LValue, LTail, RLabel, RValue, RTail, FullRightSet>
SetDiffStep<LVCons<RLabel, RValue, RTail>, FullRightSet> for LVCons<LLabel, LValue, LTail>
where
LLabel: LabelEq<RLabel>,
Self:
SetDiffMatch<LVCons<RLabel, RValue, RTail>, FullRightSet, <LLabel as LabelEq<RLabel>>::Eq>,
{
type Set = <Self as SetDiffMatch<
LVCons<RLabel, RValue, RTail>,
FullRightSet,
<LLabel as LabelEq<RLabel>>::Eq,
>>::Set;
}
pub trait SetDiffMatch<RightSet, FullRightSet, Match> {
type Set;
}
impl<LLabel, LValue, LTail, RLabel, RValue, RTail, FullRightSet>
SetDiffMatch<LVCons<RLabel, RValue, RTail>, FullRightSet, False>
for LVCons<LLabel, LValue, LTail>
where
LVCons<LLabel, LValue, LTail>: SetDiffStep<RTail, FullRightSet>,
{
type Set = <LVCons<LLabel, LValue, LTail> as SetDiffStep<RTail, FullRightSet>>::Set;
}
impl<LLabel, LValue, LTail, RLabel, RValue, RTail, FullRightSet>
SetDiffMatch<LVCons<RLabel, RValue, RTail>, FullRightSet, True>
for LVCons<LLabel, LValue, LTail>
where
LTail: SetDiffStep<RTail, FullRightSet>,
{
type Set = <LTail as SetDiffStep<RTail, FullRightSet>>::Set;
}
pub type LabelSetDiff<LeftSet, RightSet> = <LeftSet as SetDiff<RightSet>>::Set;
pub trait LookupElemByNat<N> {
type Elem;
fn elem(&self) -> &Self::Elem;
}
impl<H, T> LookupElemByNat<UTerm> for Cons<H, T> {
type Elem = H;
fn elem(&self) -> &Self::Elem {
&self.head
}
}
impl<H, T> LookupElemByNat<UInt<UTerm, B1>> for Cons<H, T>
where
T: LookupElemByNat<UTerm>,
{
type Elem = <T as LookupElemByNat<UTerm>>::Elem;
fn elem(&self) -> &Self::Elem {
self.tail.elem()
}
}
impl<H, T, N> LookupElemByNat<UInt<N, B0>> for Cons<H, T>
where
N: Sub<B1>,
T: LookupElemByNat<UInt<Sub1<N>, B1>>,
{
type Elem = <T as LookupElemByNat<UInt<Sub1<N>, B1>>>::Elem;
fn elem(&self) -> &Self::Elem {
self.tail.elem()
}
}
impl<H, T, N, B> LookupElemByNat<UInt<UInt<N, B>, B1>> for Cons<H, T>
where
T: LookupElemByNat<UInt<UInt<N, B>, B0>>,
{
type Elem = <T as LookupElemByNat<UInt<UInt<N, B>, B0>>>::Elem;
fn elem(&self) -> &Self::Elem {
self.tail.elem()
}
}
pub trait LookupNatByLabel<L> {
type Nat: Unsigned;
fn nat(&self) -> usize {
Self::Nat::to_usize()
}
}
impl<TargetL, L, V, T> LookupNatByLabel<TargetL> for LVCons<L, V, T>
where
TargetL: LabelEq<L>,
LVCons<L, V, T>: LookupNatByLabelMatch<TargetL, <TargetL as LabelEq<L>>::Eq>,
{
type Nat =
<LVCons<L, V, T> as LookupNatByLabelMatch<TargetL, <TargetL as LabelEq<L>>::Eq>>::Nat;
}
pub trait LookupNatByLabelMatch<TargetL, B> {
type Nat: Unsigned;
}
impl<TargetL, L, V, T> LookupNatByLabelMatch<TargetL, True> for LVCons<L, V, T> {
type Nat = UTerm;
}
impl<TargetL, L, V, T> LookupNatByLabelMatch<TargetL, False> for LVCons<L, V, T>
where
T: LookupNatByLabel<TargetL>,
<T as LookupNatByLabel<TargetL>>::Nat: Add<B1>,
<<T as LookupNatByLabel<TargetL>>::Nat as Add<B1>>::Output: Unsigned,
{
type Nat = Add1<<T as LookupNatByLabel<TargetL>>::Nat>;
}
pub trait LookupElemByLabel<L> {
type Elem;
fn elem(&self) -> &Self::Elem;
}
impl<L, T> LookupElemByLabel<L> for T
where
T: LookupNatByLabel<L>,
T: LookupElemByNat<<T as LookupNatByLabel<L>>::Nat>,
{
type Elem = <Self as LookupElemByNat<<Self as LookupNatByLabel<L>>::Nat>>::Elem;
fn elem(&self) -> &Self::Elem {
LookupElemByNat::<_>::elem(self)
}
}
pub trait TakeElemByNat<N> {
type Elem;
type Rest;
fn take_elem(self) -> (Self::Elem, Self::Rest);
}
impl<H, T> TakeElemByNat<UTerm> for Cons<H, T> {
type Elem = H;
type Rest = T;
fn take_elem(self) -> (H, T) {
(self.head, self.tail)
}
}
impl<H, T> TakeElemByNat<UInt<UTerm, B1>> for Cons<H, T>
where
T: TakeElemByNat<UTerm>,
{
type Elem = <T as TakeElemByNat<UTerm>>::Elem;
type Rest = Cons<H, <T as TakeElemByNat<UTerm>>::Rest>;
fn take_elem(self) -> (Self::Elem, Self::Rest) {
let (elem, rest) = self.tail.take_elem();
(elem, cons(self.head, rest))
}
}
impl<H, T, N> TakeElemByNat<UInt<N, B0>> for Cons<H, T>
where
N: Sub<B1>,
T: TakeElemByNat<UInt<Sub1<N>, B1>>,
{
type Elem = <T as TakeElemByNat<UInt<Sub1<N>, B1>>>::Elem;
type Rest = Cons<H, <T as TakeElemByNat<UInt<Sub1<N>, B1>>>::Rest>;
fn take_elem(self) -> (Self::Elem, Self::Rest) {
let (elem, rest) = self.tail.take_elem();
(elem, cons(self.head, rest))
}
}
impl<H, T, N, B> TakeElemByNat<UInt<UInt<N, B>, B1>> for Cons<H, T>
where
T: TakeElemByNat<UInt<UInt<N, B>, B0>>,
{
type Elem = <T as TakeElemByNat<UInt<UInt<N, B>, B0>>>::Elem;
type Rest = Cons<H, <T as TakeElemByNat<UInt<UInt<N, B>, B0>>>::Rest>;
fn take_elem(self) -> (Self::Elem, Self::Rest) {
let (elem, rest) = self.tail.take_elem();
(elem, cons(self.head, rest))
}
}
pub trait TakeElemByLabel<L> {
type Elem;
type Rest;
fn take_elem(self) -> (Self::Elem, Self::Rest);
}
impl<L, T> TakeElemByLabel<L> for T
where
T: LookupNatByLabel<L>,
T: TakeElemByNat<<T as LookupNatByLabel<L>>::Nat>,
{
type Elem = <Self as TakeElemByNat<<Self as LookupNatByLabel<L>>::Nat>>::Elem;
type Rest = <Self as TakeElemByNat<<Self as LookupNatByLabel<L>>::Nat>>::Rest;
fn take_elem(self) -> (Self::Elem, Self::Rest) {
TakeElemByNat::<_>::take_elem(self)
}
}
pub type ElemOf<T, Label> = <T as LookupElemByLabel<Label>>::Elem;
pub trait LookupValuedElemByLabel<L>: LookupElemByLabel<L> {
type Elem: Valued;
fn elem(&self) -> &<Self as LookupValuedElemByLabel<L>>::Elem;
}
impl<T, L> LookupValuedElemByLabel<L> for T
where
T: LookupElemByLabel<L>,
ElemOf<Self, L>: Valued,
{
type Elem = <Self as LookupElemByLabel<L>>::Elem;
fn elem(&self) -> &<Self as LookupElemByLabel<L>>::Elem {
<Self as LookupElemByLabel<L>>::elem(self)
}
}
pub type ValuedElemOf<T, Label> = <T as LookupValuedElemByLabel<Label>>::Elem;
pub type ValueOfElemOf<T, Label> = <<T as LookupValuedElemByLabel<Label>>::Elem as Valued>::Value;
pub trait LookupMarkedElemByLabel<L>: LookupElemByLabel<L> {
type Elem: Marked;
}
impl<T, L> LookupMarkedElemByLabel<L> for T
where
T: LookupElemByLabel<L>,
ElemOf<Self, L>: Marked,
{
type Elem = <Self as LookupElemByLabel<L>>::Elem;
}
pub type MarkedElemOf<T, Label> = <T as LookupMarkedElemByLabel<Label>>::Elem;
pub type MarkerOfElemOf<T, Label> = <<T as LookupMarkedElemByLabel<Label>>::Elem as Marked>::Marker;
pub trait LookupTypedElemByLabel<L>: LookupElemByLabel<L> {
type Elem: Typed;
}
impl<T, L> LookupTypedElemByLabel<L> for T
where
T: LookupElemByLabel<L>,
ElemOf<Self, L>: Typed,
{
type Elem = <Self as LookupElemByLabel<L>>::Elem;
}
pub type TypedElemOf<T, Label> = <T as LookupTypedElemByLabel<Label>>::Elem;
pub type TypeOfElemOf<T, Label> = <<T as LookupTypedElemByLabel<Label>>::Elem as Typed>::DType;
pub trait LabelSubset<LabelList> {
type Output;
}
impl<LabelList> LabelSubset<LabelList> for Nil {
type Output = Nil;
}
impl<LabelList, L, V, T> LabelSubset<LabelList> for LVCons<L, V, T>
where
LabelList: Member<L>,
LVCons<L, V, T>: LabelSubsetPred<LabelList, <LabelList as Member<L>>::IsMember>,
{
type Output =
<LVCons<L, V, T> as LabelSubsetPred<LabelList, <LabelList as Member<L>>::IsMember>>::Output;
}
pub trait LabelSubsetPred<LabelList, IsMember> {
type Output;
}
impl<LabelList, H, T> LabelSubsetPred<LabelList, True> for Cons<H, T>
where
T: LabelSubset<LabelList>,
{
type Output = Cons<H, <T as LabelSubset<LabelList>>::Output>;
}
impl<LabelList, H, T> LabelSubsetPred<LabelList, False> for Cons<H, T>
where
T: LabelSubset<LabelList>,
{
type Output = <T as LabelSubset<LabelList>>::Output;
}
pub trait Reorder<TargetOrdering> {
type Output;
fn reorder(self) -> Self::Output;
}
impl<L, V, T, TargetL, TargetV, TargetT> Reorder<LVCons<TargetL, TargetV, TargetT>>
for LVCons<L, V, T>
where
LVCons<L, V, T>: HasLabels<LVCons<TargetL, TargetV, TargetT>>,
LVCons<TargetL, TargetV, TargetT>: HasLabels<LVCons<L, V, T>>,
LVCons<TargetL, TargetV, TargetT>: Reordering<Self>,
{
type Output = <LVCons<TargetL, TargetV, TargetT> as Reordering<Self>>::Output;
fn reorder(self) -> Self::Output {
<LVCons<TargetL, TargetV, TargetT> as Reordering<Self>>::reorder(self)
}
}
pub trait Reordering<Original> {
type Output;
fn reorder(orig: Original) -> Self::Output;
}
impl Reordering<Nil> for Nil {
type Output = Nil;
fn reorder(_: Nil) -> Nil {
Nil
}
}
impl<L, V, T, TargetL, TargetV, TargetT> Reordering<LVCons<L, V, T>>
for LVCons<TargetL, TargetV, TargetT>
where
LVCons<L, V, T>: TakeElemByLabel<TargetL>,
<LVCons<L, V, T> as TakeElemByLabel<TargetL>>::Elem: Valued,
TargetT: Reordering<<LVCons<L, V, T> as TakeElemByLabel<TargetL>>::Rest>,
{
type Output = LVCons<
TargetL,
<<LVCons<L, V, T> as TakeElemByLabel<TargetL>>::Elem as Valued>::Value,
<TargetT as Reordering<<LVCons<L, V, T> as TakeElemByLabel<TargetL>>::Rest>>::Output,
>;
fn reorder(orig: LVCons<L, V, T>) -> Self::Output {
let (elem, rest) = TakeElemByLabel::<TargetL>::take_elem(orig);
LVCons {
head: Labeled::from(elem.value()),
tail: <TargetT as Reordering<_>>::reorder(rest),
}
}
}
macro_rules! subset_apply {
(
$req_trait:tt $req_fn:tt ($($req_fn_output:tt)*)
$trait_name:tt $fn_name:tt
$trait_name_pred:tt $fn_name_pred:tt
) => {
pub trait $trait_name<LabelList> {
type Output;
fn $fn_name(&self) -> Self::Output;
}
impl<LabelList> $trait_name<LabelList> for Nil {
type Output = Nil;
fn $fn_name(&self) -> Nil {
Nil
}
}
impl<LabelList, L, V, T> $trait_name<LabelList> for LVCons<L, V, T>
where
LabelList: Member<L>,
Self: $trait_name_pred<LabelList, <LabelList as Member<L>>::IsMember>
{
type Output = <LVCons<L, V, T> as $trait_name_pred<
LabelList,
<LabelList as Member<L>>::IsMember,
>>::Output;
fn $fn_name(&self) -> Self::Output {
self.$fn_name_pred()
}
}
pub trait $trait_name_pred<LabelList, IsMember> {
type Output;
fn $fn_name_pred(&self) -> Self::Output;
}
impl<LabelList, H, T> $trait_name_pred<LabelList, True> for Cons<H, T>
where
T: $trait_name<LabelList>,
H: $req_trait,
{
type Output = Cons<$($req_fn_output)*, <T as $trait_name<LabelList>>::Output>;
fn $fn_name_pred(&self) -> Self::Output {
Cons {
head: self.head.$req_fn(),
tail: self.tail.$fn_name()
}
}
}
impl<LabelList, H, T> $trait_name_pred<LabelList, False> for Cons<H, T>
where
T: $trait_name<LabelList>,
{
type Output = <T as $trait_name<LabelList>>::Output;
fn $fn_name_pred(&self) -> Self::Output {
self.tail.$fn_name()
}
}
}
}
subset_apply![
Clone clone (H)
SubsetClone subset_clone
SubsetClonePred subset_clone_pred
];
pub trait AssocLabels {
type Labels;
}
impl<Label, Value, Tail> AssocLabels for LVCons<Label, Value, Tail>
where
Tail: AssocLabels,
{
type Labels = LabelCons<Label, Tail::Labels>;
}
impl AssocLabels for Nil {
type Labels = Nil;
}
pub trait StrLabels {
fn labels<'a>() -> VecDeque<&'a str>;
fn labels_vec<'a>() -> Vec<&'a str> {
Self::labels().iter().map(|&s| s).collect::<Vec<_>>()
}
}
impl StrLabels for Nil {
fn labels<'a>() -> VecDeque<&'a str> {
VecDeque::new()
}
}
impl<L, V, T> StrLabels for LVCons<L, V, T>
where
L: LabelName,
T: StrLabels,
{
fn labels<'a>() -> VecDeque<&'a str> {
let mut previous = T::labels();
previous.push_front(L::name());
previous
}
}
impl NRows for Nil {
fn nrows(&self) -> usize {
0
}
}
impl<L, V, Tail> NRows for LVCons<L, V, Tail>
where
V: Valued,
ValueOf<V>: NRows,
{
fn nrows(&self) -> usize {
self.head.value_ref().nrows()
}
}
pub trait StrTypes {
fn str_types<'a>() -> VecDeque<&'a str>;
}
impl StrTypes for Nil {
fn str_types<'a>() -> VecDeque<&'a str> {
VecDeque::new()
}
}
impl<L, V, T> StrTypes for LVCons<L, V, T>
where
L: LabelName,
T: StrTypes,
{
fn str_types<'a>() -> VecDeque<&'a str> {
let mut previous = T::str_types();
previous.push_front(L::str_type());
previous
}
}
#[macro_export]
macro_rules! tablespace {
(@fields() -> ($($out:tt)*)) => {
declare_fields![Table; $($out)*];
pub type Fields = Fields![$($out)*];
};
(@fields(,) -> ($($out:tt)*)) => {
declare_fields![Table; $($out)*];
pub type Fields = Fields![$($out)*];
};
(@fields
(,$field_name:ident: $field_ty:ident = {$str_name:expr} $($rest:tt)*)
->
($($out:tt)*)
) => {
tablespace![@fields
($($rest)*)
->
($($out)* $field_name: $field_ty = $str_name,)
];
};
(@fields
(,$field_name:ident: $field_ty:ident $($rest:tt)*)
->
($($out:tt)*)
) => {
tablespace![@fields
($($rest)*)
->
($($out)* $field_name: $field_ty = stringify![$field_name],)
];
};
(@body($($body:tt)*)) => {
tablespace![@fields(,$($body)*) -> ()];
};
(@construct($vis:vis $tbl_name:ident)($nat:ty)($($body:tt)*)) => {
$vis mod $tbl_name {
#![allow(dead_code)]
pub type Table = $nat;
pub type Store = $crate::store::DataStore<Fields>;
pub type DataStore = Store;
pub type View = <Store as $crate::store::IntoView>::Output;
pub type DataView = View;
tablespace![@body($($body)*)];
}
};
(@continue($prev_tbl:ty)) => {};
(@continue($prev_tbl:ty)
$vis:vis table $tbl_name:ident {
$($body:tt)*
}
$($rest:tt)*
) => {
tablespace![@construct($vis $tbl_name)($prev_tbl)($($body)*)];
tablespace![@continue($crate::typenum::Add1<$prev_tbl>) $($rest)*];
};
(
$vis:vis table $tbl_name:ident {
$($body:tt)*
}
$($rest:tt)*
) => {
tablespace![@construct($vis $tbl_name)($crate::typenum::U0)($($body)*)];
tablespace![@continue($crate::typenum::Add1<$crate::typenum::U0>) $($rest)*];
}
}
#[macro_export]
macro_rules! nat_label {
($label:ident, $tbl:ty, $nat:ty, $dtype:ty, $name:expr) => {
#[derive(Debug, Clone)]
pub struct $label;
impl $crate::label::Identifier for $label {
type Ident = $crate::label::Ident<$tbl, $nat>;
type Table = $tbl;
type Natural = $nat;
}
impl $crate::label::Label for $label {
const NAME: &'static str = $name;
const TYPE: &'static str = stringify![$dtype];
}
impl $crate::label::Typed for $label {
type DType = $dtype;
}
};
}
#[macro_export]
macro_rules! first_label {
($label:ident, $tbl:ty, $dtype:ty) => {
first_label![$label, $tbl, $dtype, stringify![$label]];
};
($label:ident, $tbl:ty, $dtype:ty, $name:expr) => {
nat_label![$label, $tbl, $crate::typenum::consts::U0, $dtype, $name];
};
}
#[macro_export]
macro_rules! next_label {
($label:ident, $prev:ident, $dtype:ty) => {
next_label![$label, $prev, $dtype, stringify![$label]];
};
($label:ident, $prev:ident, $dtype:ty, $name:expr) => {
nat_label![
$label,
$crate::label::TblOf<$prev>,
$crate::typenum::Add1<$crate::label::NatOf<$prev>>,
$dtype,
$name
];
};
}
#[macro_export]
macro_rules! Labels {
(@labels()) => { $crate::cons::Nil };
(@labels($label:ident, $($rest:tt,)*)) =>
{
$crate::label::LCons<$label, Labels![@labels($($rest,)*)]>
};
(@labels($label:path, $($rest:tt,)*)) =>
{
$crate::label::LCons<$label, Labels![@labels($($rest,)*)]>
};
($($label:ident),*$(,)*) =>
{
Labels![@labels($($label,)*)]
};
($($label:path),*$(,)*) =>
{
Labels![@labels($($label,)*)]
}
}
#[macro_export]
macro_rules! declare_fields
{
(@step($tbl:ty)($prev_label:ident)()) => {};
(@step
($tbl:ty)
($prev_label:ident)
($label:ident: $dtype:ident = $name:expr, $($rest:tt)*)
)
=>
{
next_label![$label, $prev_label, $dtype, $name];
declare_fields![@step
($tbl)
($label)
($($rest)*)
];
};
(@step($tbl:ty)($prev_label:ident)($label:ident: $dtype:ident = $name:expr))
=>
{
declare_fields![@step($tbl)($prev_label)($label: $dtype,)]
};
(@start
($tbl:ty)
($label:ident: $dtype:ident = $name:expr, $($rest:tt)*)
)
=>
{
first_label![$label, $tbl, $dtype, $name];
declare_fields![@step
($tbl)
($label)
($($rest)*)
];
};
(@start($tbl:ty)($label:ident: $dtype:ident = $name:expr))
=>
{
declare_fields![@step($tbl)($label: $dtype = $name,)]
};
($tbl:ty; $($fields:tt)*) => {
declare_fields![@start($tbl)($($fields)*)];
};
}
#[macro_export]
macro_rules! Fields {
(@fields()) => { $crate::cons::Nil };
(@fields(
$label:ident: $dtype:ident $(= $name:expr)*,
$($rest_label:ident: $rest_dtype:ident $(= $rest_name:expr)*,)*)
)
=>
{
$crate::fieldlist::FieldCons<
$label,
$dtype,
Fields![@fields($($rest_label: $rest_dtype,)*)]
>
};
($($label:ident: $dtype:ident $(= $name:expr)*),*$(,)*) =>
{
Fields![@fields($($label: $dtype,)*)]
};
($existing:ident .. $($label:ident: $dtype:ident),*$(,)*) =>
{
<$existing as $crate::cons::Append<Fields![@fields($($label: $dtype,)*)]>>::Appended
};
($($label:ident: $dtype:ident),*$(,)* .. $existing:ident) =>
{
<Fields![@fields($($label: $dtype,)*)] as $crate::cons::Append<$existing>>::Appended
}
}
#[macro_export]
macro_rules! table {
($($label:ty = [$($value:expr),*];)*) => {{
$crate::store::DataStore::<$crate::cons::Nil>::empty()
$(
.push_back_field::<$label, _>(
$crate::field::FieldData::from_boxed_slice(Box::new([$($value),*]))
)
)*
.into_view()
}}
}
#[cfg(test)]
mod tests {
use super::*;
use cons::*;
use typenum::{
consts::{U0, U1, U2, U3, U4},
Bit,
};
pub type SampleTable = U0;
first_label![ImALabel, U0, u64];
next_label![ImAnotherLabel, ImALabel, u64];
#[test]
fn type_eq() {
assert!(<U1 as IdentEq<U1>>::Eq::to_bool());
assert!(!<U1 as IdentEq<U4>>::Eq::to_bool());
assert!(<ImALabel as LabelEq<ImALabel>>::Eq::to_bool());
assert!(!<ImALabel as LabelEq<ImAnotherLabel>>::Eq::to_bool());
}
pub type NumberTable = Add1<SampleTable>;
first_label![F0, NumberTable, u64];
next_label![F1, F0, f64];
next_label![F2, F1, i64];
next_label![F3, F2, String];
next_label![F4, F3, f32];
next_label![F5, F4, f32];
next_label![F6, F5, f32];
next_label![F7, F6, f32];
#[test]
fn lookup() {
let list = LVCons {
head: Labeled::<F0, _>::from(6u64),
tail: LVCons {
head: Labeled::<F1, _>::from(5.3f64),
tail: LVCons {
head: Labeled::<F2, _>::from(-3i64),
tail: LVCons {
head: Labeled::<F3, _>::from("Hello".to_string()),
tail: LVCons {
head: Labeled::<F4, _>::from(3.2f32),
tail: Nil,
},
},
},
},
};
assert_eq!(LookupElemByNat::<U0>::elem(&list).value, 6u64);
assert_eq!(LookupElemByNat::<U1>::elem(&list).value, 5.3);
assert_eq!(LookupElemByNat::<U2>::elem(&list).value, -3i64);
assert_eq!(
LookupElemByNat::<U3>::elem(&list).value,
"Hello".to_string()
);
assert_eq!(LookupElemByNat::<U4>::elem(&list).value, 3.2f32);
assert_eq!(LookupNatByLabel::<F0>::nat(&list), 0);
assert_eq!(LookupNatByLabel::<F1>::nat(&list), 1);
assert_eq!(LookupNatByLabel::<F2>::nat(&list), 2);
assert_eq!(LookupNatByLabel::<F3>::nat(&list), 3);
assert_eq!(LookupNatByLabel::<F4>::nat(&list), 4);
assert_eq!(LookupElemByLabel::<F0>::elem(&list).value, 6u64);
assert_eq!(LookupElemByLabel::<F1>::elem(&list).value, 5.3);
assert_eq!(LookupElemByLabel::<F2>::elem(&list).value, -3i64);
assert_eq!(
LookupElemByLabel::<F3>::elem(&list).value,
"Hello".to_string()
);
assert_eq!(LookupElemByLabel::<F4>::elem(&list).value, 3.2f32);
let list = LVCons {
head: Labeled::<F5, _>::from(3u32),
tail: list,
};
assert_eq!(LookupNatByLabel::<F0>::nat(&list), 1);
assert_eq!(LookupNatByLabel::<F1>::nat(&list), 2);
assert_eq!(LookupNatByLabel::<F2>::nat(&list), 3);
assert_eq!(LookupNatByLabel::<F3>::nat(&list), 4);
assert_eq!(LookupNatByLabel::<F4>::nat(&list), 5);
assert_eq!(LookupNatByLabel::<F5>::nat(&list), 0);
assert_eq!(LookupElemByLabel::<F0>::elem(&list).value, 6u64);
assert_eq!(LookupElemByLabel::<F1>::elem(&list).value, 5.3);
assert_eq!(LookupElemByLabel::<F2>::elem(&list).value, -3i64);
assert_eq!(
LookupElemByLabel::<F3>::elem(&list).value,
"Hello".to_string()
);
assert_eq!(LookupElemByLabel::<F4>::elem(&list).value, 3.2f32);
assert_eq!(LookupElemByLabel::<F5>::elem(&list).value, 3u32);
}
#[test]
fn filter() {
type SampleLabels = LVCons<
F0,
u64,
LVCons<F1, f64, LVCons<F2, i64, LVCons<F3, String, LVCons<F4, f32, Nil>>>>,
>;
{
type Filtered = <SampleLabels as LabelSubset<Labels![]>>::Output;
assert_eq!(length![Filtered], 0);
}
{
type Filtered = <Nil as LabelSubset<Labels![F1, F3]>>::Output;
assert_eq!(length![Filtered], 0);
}
{
type Filtered = <SampleLabels as LabelSubset<Labels![F3]>>::Output;
assert_eq!(length![Filtered], 1);
}
{
type Filtered = <SampleLabels as LabelSubset<Labels![F1, F2, F4]>>::Output;
assert_eq!(length![Filtered], 3);
{
type Refiltered = <Filtered as LabelSubset<Labels![F1, F2, F4]>>::Output;
assert_eq!(length![Refiltered], 3);
}
{
type Refiltered = <Filtered as LabelSubset<Labels![F1, F2]>>::Output;
assert_eq!(length![Refiltered], 2);
}
{
type Refiltered = <Filtered as LabelSubset<Labels![F3, F0]>>::Output;
assert_eq!(length![Refiltered], 0);
}
{
type Refiltered = <Filtered as LabelSubset<Labels![F0, F1, F2, F3, F4]>>::Output;
assert_eq!(length![Refiltered], 3);
}
}
{
type Filtered = <SampleLabels as LabelSubset<Labels![F1, F2, F4, F5]>>::Output;
assert_eq!(length![Filtered], 3);
}
{
type Filtered = <SampleLabels as LabelSubset<Labels![F5, F6, F7]>>::Output;
assert_eq!(length![Filtered], 0);
}
{
type Filtered = <SampleLabels as LabelSubset<Labels![F2, F2, F2]>>::Output;
assert_eq!(length![Filtered], 1);
}
{
type Filtered = <SampleLabels as LabelSubset<Labels![F2, F2, F3]>>::Output;
assert_eq!(length![Filtered], 2);
}
}
#[test]
fn reorder() {
type LSet = LVCons<F0, u64, LVCons<F1, f64, LVCons<F2, i64, Nil>>>;
assert_eq!(["F0", "F1", "F2"], <LSet as StrLabels>::labels_vec()[..]);
type NewOrder = Labels![F0, F2, F1];
type Reordered = <LSet as Reorder<NewOrder>>::Output;
assert_eq!(
["F0", "F2", "F1"],
<Reordered as StrLabels>::labels_vec()[..]
);
let orig = LVCons {
head: Labeled::<F0, _>::from(6u64),
tail: LVCons {
head: Labeled::<F1, _>::from(5.3f64),
tail: LVCons {
head: Labeled::<F2, _>::from(-3i64),
tail: Nil,
},
},
};
assert_eq!(LookupElemByNat::<U0>::elem(&orig).value, 6u64);
assert_eq!(LookupElemByNat::<U1>::elem(&orig).value, 5.3);
assert_eq!(LookupElemByNat::<U2>::elem(&orig).value, -3i64);
let reordered: Reordered = Reorder::<NewOrder>::reorder(orig);
assert_eq!(LookupElemByNat::<U0>::elem(&reordered).value, 6u64);
assert_eq!(LookupElemByNat::<U1>::elem(&reordered).value, -3i64);
assert_eq!(LookupElemByNat::<U2>::elem(&reordered).value, 5.3);
}
#[test]
fn set_diff() {
type LSet1 = LCons<F0, LCons<F1, LCons<F2, Nil>>>;
type LSet2 = LCons<F4, LCons<F1, LCons<F2, Nil>>>;
type LSet3 = LCons<F1, Nil>;
type LSet4 = LCons<F4, Nil>;
assert_eq!(
["F0"],
<LabelSetDiff<LSet1, LSet2> as StrLabels>::labels_vec()[..]
);
assert_eq!(
["F4"],
<LabelSetDiff<LSet2, LSet1> as StrLabels>::labels_vec()[..]
);
assert_eq!(
["F0", "F2"],
<LabelSetDiff<LSet1, LSet3> as StrLabels>::labels_vec()[..]
);
assert_eq!(
["F4", "F2"],
<LabelSetDiff<LSet2, LSet3> as StrLabels>::labels_vec()[..]
);
assert_eq!(
["F1", "F2"],
<LabelSetDiff<LSet2, LSet4> as StrLabels>::labels_vec()[..]
);
assert_eq!(
["F0", "F1", "F2"],
<LabelSetDiff<LSet1, LSet4> as StrLabels>::labels_vec()[..]
);
assert_eq!(
[] as [&str; 0],
<LabelSetDiff<LSet3, LSet1> as StrLabels>::labels_vec()[..]
);
assert_eq!(
["F4"],
<LabelSetDiff<LSet4, LSet1> as StrLabels>::labels_vec()[..]
);
assert_eq!(
[] as [&str; 0],
<LabelSetDiff<LSet4, LSet2> as StrLabels>::labels_vec()[..]
);
assert_eq!(
[] as [&str; 0],
<LabelSetDiff<Nil, Nil> as StrLabels>::labels_vec()[..]
);
assert_eq!(
[] as [&str; 0],
<LabelSetDiff<Nil, LSet2> as StrLabels>::labels_vec()[..]
);
assert_eq!(
["F4", "F1", "F2"],
<LabelSetDiff<LSet2, Nil> as StrLabels>::labels_vec()[..]
);
assert_eq!(
[] as [&str; 0],
<LabelSetDiff<LSet2, LSet2> as StrLabels>::labels_vec()[..]
);
}
}