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::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<P: Peano> {
fn discr(&self) -> Discr<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> {
fn new_unchecked(u: u32) -> Self {
Self(u, PhantomData)
Self(u, Default::default())
}
fn dispatch<H: DiscrHandler<P>>(&self, h: H) -> H::Output {
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
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<P0> for EnumDispatch<'a, Enum<L>, F>
impl<'a, I, F> DiscrHandler<P0> for DispatchIndexable<'a, I, F>
where
L: Indexable<P0>,
L::Element: Copy,
F: VariantHandler<P0, Args=L::Element>,
I: Indexable<P0>,
I::Element: Copy,
F: VariantHandler<P0, Args=I::Element>,
{
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<PNext<P>> for EnumDispatch<'a, Enum<L>, F>
impl<'a, I, F, P: Peano> DiscrHandler<PNext<P>> for DispatchIndexable<'a, I, F>
where
L: Indexable<PNext<P>>,
L::Element: Copy,
F: VariantHandler<PNext<P>, Args=L::Element, Output=<Self as DiscrHandler<P>>::Output>,
I: Indexable<PNext<P>>,
I::Element: Copy,
F: VariantHandler<PNext<P>, Args=I::Element, Output=<Self as DiscrHandler<P>>::Output>,
Self: DiscrHandler<P>,
{
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>(L);
struct Enum<D, L>(D, L);
trait DiscriminantedEnum<P: Peano>: Sized {
fn discr(&self) -> Discr<P>;
fn dispatch<'a, F>(&'a self, f: F) -> <EnumDispatch<'a, Self, F> as DiscrHandler<P>>::Output
where
EnumDispatch<'a, Self, F>: DiscrHandler<P>
{
self.discr().dispatch(EnumDispatch::new(self, f))
trait EnumRequirements {
type MaxDiscr: Peano;
fn discr(&self) -> Discr<Self::MaxDiscr>;
}
impl<D, L> EnumRequirements for Enum<(D,), L>
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")]
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())
}
}
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);
#[derive(Default)]
#[derive(Copy, Clone, Default, PartialEq)]
pub struct P0;
pub type P1 = PNext<P0>;
@@ -11,9 +11,12 @@ pub type P5 = PNext<P4>;
pub type P6 = PNext<P5>;
pub type P7 = PNext<P6>;
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<P: Peano> Peano for PNext<P> {
type Next = PNext<PNext<P>>;
type PrevOrZero = P;
type Unit = ();
const VALUE: u32 = 1 + P::VALUE;
}
impl<P: Peano> PeanoNonZero for PNext<P> {