coremem_types: enumerated: allow folding the enum into the first element

This commit is contained in:
2022-07-21 18:28:20 -07:00
parent b15bad434e
commit 9153dfbb7a
3 changed files with 89 additions and 30 deletions

View File

@@ -1,13 +1,25 @@
use crate::compound::peano::{LessThan, P0, P1, P2, P3, Peano, PeanoNonZero, PNext}; 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; use core::marker::PhantomData;
// anything which can encode a discriminant up to *and including* P
pub trait DiscriminantCodable<P: Peano> {
fn discr(&self) -> Discr<P>;
}
// discriminant which encodes up to *and including* P. // discriminant which encodes up to *and including* P.
pub struct Discr<P: Peano>(u32, PhantomData<P>); #[derive(Copy, Clone, Default, PartialEq)]
pub struct Discr<P: Peano>(u32, P::Unit);
impl<P: Peano> DiscriminantCodable<P> for Discr<P> {
fn discr(&self) -> Self {
*self
}
}
impl<P: Peano> Discr<P> { impl<P: Peano> Discr<P> {
fn new_unchecked(u: u32) -> Self { fn new_unchecked(u: u32) -> Self {
Self(u, PhantomData) Self(u, Default::default())
} }
fn dispatch<H: DiscrHandler<P>>(&self, h: H) -> H::Output { fn dispatch<H: DiscrHandler<P>>(&self, h: H) -> H::Output {
match self.0 { match self.0 {
@@ -33,59 +45,88 @@ pub trait VariantHandler<N: Peano> {
} }
/// helper used to call F with some (yet-to-be-determined) variant of E /// helper used to call F with some (yet-to-be-determined) variant of E
struct EnumDispatch<'a, E, F> { struct DispatchIndexable<'a, I, F> {
enum_: &'a E, indexable: &'a I,
f: F, f: F,
} }
impl<'a, E, F> EnumDispatch<'a, E, F> { impl<'a, I, F> DispatchIndexable<'a, I, F> {
fn new(enum_: &'a E, f: F) -> Self { fn new(indexable: &'a I, f: F) -> Self {
Self { enum_, f } Self { indexable, f }
} }
} }
impl<'a, L, F> DiscrHandler<P0> for EnumDispatch<'a, Enum<L>, F> impl<'a, I, F> DiscrHandler<P0> for DispatchIndexable<'a, I, F>
where where
L: Indexable<P0>, I: Indexable<P0>,
L::Element: Copy, I::Element: Copy,
F: VariantHandler<P0, Args=L::Element>, F: VariantHandler<P0, Args=I::Element>,
{ {
type Output = F::Output; type Output = F::Output;
type PrevOrPanic = Self; type PrevOrPanic = Self;
fn call(self) -> Self::Output { fn call(self) -> Self::Output {
self.f.call(self.enum_.0.get()) self.f.call(self.indexable.get())
} }
fn prev(self) -> Self::PrevOrPanic { fn prev(self) -> Self::PrevOrPanic {
unimplemented!() unimplemented!()
} }
} }
impl<'a, L, F, P: Peano> DiscrHandler<PNext<P>> for EnumDispatch<'a, Enum<L>, F> impl<'a, I, F, P: Peano> DiscrHandler<PNext<P>> for DispatchIndexable<'a, I, F>
where where
L: Indexable<PNext<P>>, I: Indexable<PNext<P>>,
L::Element: Copy, I::Element: Copy,
F: VariantHandler<PNext<P>, Args=L::Element, Output=<Self as DiscrHandler<P>>::Output>, F: VariantHandler<PNext<P>, Args=I::Element, Output=<Self as DiscrHandler<P>>::Output>,
Self: DiscrHandler<P>, Self: DiscrHandler<P>,
{ {
type Output = F::Output; type Output = F::Output;
type PrevOrPanic = Self; type PrevOrPanic = Self;
fn call(self) -> Self::Output { fn call(self) -> Self::Output {
self.f.call(self.enum_.0.get()) self.f.call(self.indexable.get())
} }
fn prev(self) -> Self::PrevOrPanic { fn prev(self) -> Self::PrevOrPanic {
self self
} }
} }
pub struct Enum<L>(L); struct Enum<D, L>(D, L);
trait DiscriminantedEnum<P: Peano>: Sized { trait EnumRequirements {
fn discr(&self) -> Discr<P>; type MaxDiscr: Peano;
fn dispatch<'a, F>(&'a self, f: F) -> <EnumDispatch<'a, Self, F> as DiscrHandler<P>>::Output fn discr(&self) -> Discr<Self::MaxDiscr>;
where }
EnumDispatch<'a, Self, F>: DiscrHandler<P>
{ impl<D, L> EnumRequirements for Enum<(D,), L>
self.discr().dispatch(EnumDispatch::new(self, f)) where
D: DiscriminantCodable<<<L as list::Meta>::Length as PeanoNonZero>::Prev>,
L: list::Meta,
{
type MaxDiscr = <<L as list::Meta>::Length as PeanoNonZero>::Prev;
fn discr(&self) -> Discr<Self::MaxDiscr> {
self.0.0.discr()
}
}
impl<L> EnumRequirements for Enum<(), L>
where
L: list::Meta + Indexable<P0>,
list::ElementAt<P0, L>: Copy + DiscriminantCodable<<<L as list::Meta>::Length as PeanoNonZero>::Prev>,
{
type MaxDiscr = <<L as list::Meta>::Length as PeanoNonZero>::Prev;
fn discr(&self) -> Discr<Self::MaxDiscr> {
self.1.get().discr()
}
}
impl<D, L> Enum<D, L>
where Self: EnumRequirements
{
fn dispatch<'a, F>(&'a self, f: F) -> <DispatchIndexable<'a, L, F> as DiscrHandler<<Self as EnumRequirements>::MaxDiscr>>::Output
where
DispatchIndexable<'a, L, F>: DiscrHandler<<Self as EnumRequirements>::MaxDiscr>
{
self.discr().dispatch(DispatchIndexable::new(&self.1, f))
} }
} }

View File

@@ -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")] #[cfg(feature = "serde")]
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
@@ -96,3 +96,16 @@ impl<E0, E1, E2, E3> IntoList for (E0, E1, E2, E3) {
Node::new(self.0, (self.1, self.2, self.3).into_list()) Node::new(self.0, (self.1, self.2, self.3).into_list())
} }
} }
pub trait Meta {
type Length: PeanoNonZero;
}
impl<H> Meta for Node<H, Null> {
type Length = P1;
}
impl<H, T: Meta> Meta for Node<H, T> {
type Length = PNext<T::Length>;
}
pub type ElementAt<P, L> = <L as Indexable<P>>::Element;

View File

@@ -1,6 +1,6 @@
#[derive(Default)] #[derive(Copy, Clone, Default, PartialEq)]
pub struct PNext<P>(P); pub struct PNext<P>(P);
#[derive(Default)] #[derive(Copy, Clone, Default, PartialEq)]
pub struct P0; pub struct P0;
pub type P1 = PNext<P0>; pub type P1 = PNext<P0>;
@@ -11,9 +11,12 @@ pub type P5 = PNext<P4>;
pub type P6 = PNext<P5>; pub type P6 = PNext<P5>;
pub type P7 = PNext<P6>; pub type P7 = PNext<P6>;
pub trait Peano: Default { pub trait Peano: Copy + Clone + Default + PartialEq {
type Next: PeanoNonZero; type Next: PeanoNonZero;
type PrevOrZero: Peano; 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; const VALUE: u32;
} }
@@ -24,11 +27,13 @@ pub trait PeanoNonZero: Peano {
impl Peano for P0 { impl Peano for P0 {
type Next = P1; type Next = P1;
type PrevOrZero = P0; type PrevOrZero = P0;
type Unit = ();
const VALUE: u32 = 0; const VALUE: u32 = 0;
} }
impl<P: Peano> Peano for PNext<P> { impl<P: Peano> Peano for PNext<P> {
type Next = PNext<PNext<P>>; type Next = PNext<PNext<P>>;
type PrevOrZero = P; type PrevOrZero = P;
type Unit = ();
const VALUE: u32 = 1 + P::VALUE; const VALUE: u32 = 1 + P::VALUE;
} }
impl<P: Peano> PeanoNonZero for PNext<P> { impl<P: Peano> PeanoNonZero for PNext<P> {