diff --git a/crates/types/src/compound/enumerated.rs b/crates/types/src/compound/enumerated.rs index 75ad395..b35d687 100644 --- a/crates/types/src/compound/enumerated.rs +++ b/crates/types/src/compound/enumerated.rs @@ -1,13 +1,25 @@ use crate::compound::peano::{LessThan, P0, P1, P2, P3, Peano, PeanoNonZero, PNext}; -use crate::compound::list::{Indexable, IntoList, List}; +use crate::compound::list::{self, Indexable, IntoList, List}; use core::marker::PhantomData; +// anything which can encode a discriminant up to *and including* P +pub trait DiscriminantCodable { + fn discr(&self) -> Discr

; +} + // discriminant which encodes up to *and including* P. -pub struct Discr(u32, PhantomData

); +#[derive(Copy, Clone, Default, PartialEq)] +pub struct Discr(u32, P::Unit); + +impl DiscriminantCodable

for Discr

{ + fn discr(&self) -> Self { + *self + } +} impl Discr

{ fn new_unchecked(u: u32) -> Self { - Self(u, PhantomData) + Self(u, Default::default()) } fn dispatch>(&self, h: H) -> H::Output { match self.0 { @@ -33,59 +45,88 @@ pub trait VariantHandler { } /// helper used to call F with some (yet-to-be-determined) variant of E -struct EnumDispatch<'a, E, F> { - enum_: &'a E, +struct DispatchIndexable<'a, I, F> { + indexable: &'a I, f: F, } -impl<'a, E, F> EnumDispatch<'a, E, F> { - fn new(enum_: &'a E, f: F) -> Self { - Self { enum_, f } +impl<'a, I, F> DispatchIndexable<'a, I, F> { + fn new(indexable: &'a I, f: F) -> Self { + Self { indexable, f } } } -impl<'a, L, F> DiscrHandler for EnumDispatch<'a, Enum, F> +impl<'a, I, F> DiscrHandler for DispatchIndexable<'a, I, F> where - L: Indexable, - L::Element: Copy, - F: VariantHandler, + I: Indexable, + I::Element: Copy, + F: VariantHandler, { type Output = F::Output; type PrevOrPanic = Self; fn call(self) -> Self::Output { - self.f.call(self.enum_.0.get()) + self.f.call(self.indexable.get()) } fn prev(self) -> Self::PrevOrPanic { unimplemented!() } } -impl<'a, L, F, P: Peano> DiscrHandler> for EnumDispatch<'a, Enum, F> +impl<'a, I, F, P: Peano> DiscrHandler> for DispatchIndexable<'a, I, F> where - L: Indexable>, - L::Element: Copy, - F: VariantHandler, Args=L::Element, Output=>::Output>, + I: Indexable>, + I::Element: Copy, + F: VariantHandler, Args=I::Element, Output=>::Output>, Self: DiscrHandler

, { type Output = F::Output; type PrevOrPanic = Self; fn call(self) -> Self::Output { - self.f.call(self.enum_.0.get()) + self.f.call(self.indexable.get()) } fn prev(self) -> Self::PrevOrPanic { self } } -pub struct Enum(L); +struct Enum(D, L); -trait DiscriminantedEnum: Sized { - fn discr(&self) -> Discr

; - fn dispatch<'a, F>(&'a self, f: F) -> as DiscrHandler

>::Output - where - EnumDispatch<'a, Self, F>: DiscrHandler

- { - self.discr().dispatch(EnumDispatch::new(self, f)) +trait EnumRequirements { + type MaxDiscr: Peano; + fn discr(&self) -> Discr; +} + +impl EnumRequirements for Enum<(D,), L> +where + D: DiscriminantCodable<<::Length as PeanoNonZero>::Prev>, + L: list::Meta, +{ + type MaxDiscr = <::Length as PeanoNonZero>::Prev; + fn discr(&self) -> Discr { + self.0.0.discr() + } +} + +impl EnumRequirements for Enum<(), L> +where + L: list::Meta + Indexable, + list::ElementAt: Copy + DiscriminantCodable<<::Length as PeanoNonZero>::Prev>, +{ + type MaxDiscr = <::Length as PeanoNonZero>::Prev; + fn discr(&self) -> Discr { + self.1.get().discr() + } +} + + +impl Enum +where Self: EnumRequirements +{ + fn dispatch<'a, F>(&'a self, f: F) -> as DiscrHandler<::MaxDiscr>>::Output + where + DispatchIndexable<'a, L, F>: DiscrHandler<::MaxDiscr> + { + self.discr().dispatch(DispatchIndexable::new(&self.1, f)) } } diff --git a/crates/types/src/compound/list/flat.rs b/crates/types/src/compound/list/flat.rs index e8156b5..a2711bf 100644 --- a/crates/types/src/compound/list/flat.rs +++ b/crates/types/src/compound/list/flat.rs @@ -1,4 +1,4 @@ -use crate::compound::peano::{LessThan, P0, P1, P2, P3, Peano}; +use crate::compound::peano::{LessThan, P0, P1, P2, P3, Peano, PeanoNonZero, PNext}; #[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; @@ -96,3 +96,16 @@ impl IntoList for (E0, E1, E2, E3) { Node::new(self.0, (self.1, self.2, self.3).into_list()) } } + +pub trait Meta { + type Length: PeanoNonZero; +} + +impl Meta for Node { + type Length = P1; +} +impl Meta for Node { + type Length = PNext; +} + +pub type ElementAt = >::Element; diff --git a/crates/types/src/compound/peano.rs b/crates/types/src/compound/peano.rs index 59f570a..cbc9745 100644 --- a/crates/types/src/compound/peano.rs +++ b/crates/types/src/compound/peano.rs @@ -1,6 +1,6 @@ -#[derive(Default)] +#[derive(Copy, Clone, Default, PartialEq)] pub struct PNext

(P); -#[derive(Default)] +#[derive(Copy, Clone, Default, PartialEq)] pub struct P0; pub type P1 = PNext; @@ -11,9 +11,12 @@ pub type P5 = PNext; pub type P6 = PNext; pub type P7 = PNext; -pub trait Peano: Default { +pub trait Peano: Copy + Clone + Default + PartialEq { type Next: PeanoNonZero; type PrevOrZero: Peano; + /// always set to () + /// this exists to allow Peano numbers to be used as struct parameters without PhantomData + type Unit: Copy + Clone + Default + PartialEq; const VALUE: u32; } @@ -24,11 +27,13 @@ pub trait PeanoNonZero: Peano { impl Peano for P0 { type Next = P1; type PrevOrZero = P0; + type Unit = (); const VALUE: u32 = 0; } impl Peano for PNext

{ type Next = PNext>; type PrevOrZero = P; + type Unit = (); const VALUE: u32 = 1 + P::VALUE; } impl PeanoNonZero for PNext

{