use crate::const_known::{No, Yes, YesOrNo};
use super::{
array_vec::ArrayVec, collect_nothing::CollectNothing, count::Count, lead_vec::LeadVec,
HasConstDummyValue,
};
#[non_exhaustive]
pub enum KnownCollection<V: IsKnownCollection<T>, T: Copy> {
ArrayVec(V::ArrayVec, V::ArrayVecType),
LeadVec(V::LeadVec, V::LeadVecType),
Count(V::Count, Count),
CollectNothing(V::CollectNothing, CollectNothing),
}
impl<V: IsKnownCollection<T>, T: Copy> Copy for KnownCollection<V, T> {}
impl<V: IsKnownCollection<T>, T: Copy> Clone for KnownCollection<V, T> {
fn clone(&self) -> Self {
*self
}
}
impl<V: IsKnownCollection<T>, T: Copy> std::fmt::Debug for KnownCollection<V, T>
where
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ArrayVec(_, this) => SelfDebugDerive::self_debug(this).fmt(f),
Self::LeadVec(_, this) => SelfDebugDerive::self_debug(this).fmt(f),
Self::Count(_, this) => this.fmt(f),
Self::CollectNothing(_, this) => this.fmt(f),
}
}
}
mod sealed {
pub trait IsKnownCollection<T> {}
pub trait IsArrayVec {}
pub trait IsLeadVec {}
}
pub trait SelfDebugDerive<T: ?Sized> {
type SelfDebug: std::fmt::Debug
where
T: std::fmt::Debug;
fn self_debug(this: &Self) -> &Self::SelfDebug
where
T: std::fmt::Debug;
}
pub trait IsArrayVec: sealed::IsArrayVec + SelfDebugDerive<Self::Item> {
type Item;
const CAP: usize;
}
impl<T, const N: usize> sealed::IsArrayVec for ArrayVec<T, N> {}
impl<T, const N: usize> SelfDebugDerive<T> for ArrayVec<T, N> {
type SelfDebug = Self
where
T: std::fmt::Debug;
fn self_debug(this: &Self) -> &Self::SelfDebug
where
T: std::fmt::Debug,
{
this
}
}
impl<T, const N: usize> IsArrayVec for ArrayVec<T, N> {
type Item = T;
const CAP: usize = N;
}
pub trait IsLeadVec: sealed::IsLeadVec + SelfDebugDerive<Self::Item> {
type Item;
}
impl<T, const N: usize> sealed::IsLeadVec for LeadVec<T, N> {}
impl<T, const N: usize> SelfDebugDerive<T> for LeadVec<T, N> {
type SelfDebug = Self
where
T: std::fmt::Debug;
fn self_debug(this: &Self) -> &Self::SelfDebug
where
T: std::fmt::Debug,
{
this
}
}
impl<T, const N: usize> IsLeadVec for LeadVec<T, N> {
type Item = T;
}
pub trait IsKnownCollection<T: Copy>: Sized + sealed::IsKnownCollection<T> {
type ArrayVecType: IsArrayVec<Item = T> + Copy;
type ArrayVec: YesOrNo;
type LeadVecType: IsLeadVec<Item = T> + Copy;
type LeadVec: YesOrNo;
type Count: YesOrNo;
type CollectNothing: YesOrNo;
}
pub trait IsKnownCollectionWithConstEmpty<T: Copy>: IsKnownCollection<T> + Sized {
const EMPTY_COLLECTION: Self;
const EMPTY_COLLECTION_AS_KNOWN: KnownCollection<Self, T>;
}
impl<T, const CAP: usize> sealed::IsKnownCollection<T> for ArrayVec<T, CAP> {}
impl<T: Copy, const CAP: usize> IsKnownCollection<T> for ArrayVec<T, CAP> {
type ArrayVecType = Self;
type ArrayVec = Yes;
type LeadVecType = LeadVec<T, 0>;
type LeadVec = No;
type Count = No;
type CollectNothing = No;
}
impl<T: Copy + HasConstDummyValue, const CAP: usize> IsKnownCollectionWithConstEmpty<T>
for ArrayVec<T, CAP>
{
const EMPTY_COLLECTION: Self = Self::EMPTY;
const EMPTY_COLLECTION_AS_KNOWN: KnownCollection<Self, T> =
KnownCollection::<Self, T>::from_variant(Self::EMPTY);
}
impl<T, const CAP: usize> sealed::IsKnownCollection<T> for LeadVec<T, CAP> {}
impl<T: Copy, const CAP: usize> IsKnownCollection<T> for LeadVec<T, CAP> {
type ArrayVecType = ArrayVec<T, 0>;
type ArrayVec = No;
type LeadVecType = Self;
type LeadVec = Yes;
type Count = No;
type CollectNothing = No;
}
impl<T: Copy + HasConstDummyValue, const CAP: usize> IsKnownCollectionWithConstEmpty<T>
for LeadVec<T, CAP>
{
const EMPTY_COLLECTION: Self = Self::EMPTY;
const EMPTY_COLLECTION_AS_KNOWN: KnownCollection<Self, T> =
KnownCollection::<Self, T>::from_variant(Self::EMPTY);
}
impl<T> sealed::IsKnownCollection<T> for Count {}
impl<T: Copy> IsKnownCollection<T> for Count {
type ArrayVecType = ArrayVec<T, 0>;
type ArrayVec = No;
type LeadVecType = LeadVec<T, 0>;
type LeadVec = No;
type Count = Yes;
type CollectNothing = No;
}
impl<T: Copy> IsKnownCollectionWithConstEmpty<T> for Count {
const EMPTY_COLLECTION: Self = Self::EMPTY;
const EMPTY_COLLECTION_AS_KNOWN: KnownCollection<Self, T> =
KnownCollection::<Self, T>::from_variant(Self::EMPTY);
}
impl<T> sealed::IsKnownCollection<T> for CollectNothing {}
impl<T: Copy> IsKnownCollection<T> for CollectNothing {
type ArrayVecType = ArrayVec<T, 0>;
type ArrayVec = No;
type LeadVecType = LeadVec<T, 0>;
type LeadVec = No;
type Count = No;
type CollectNothing = Yes;
}
impl<T: Copy> IsKnownCollectionWithConstEmpty<T> for CollectNothing {
const EMPTY_COLLECTION: Self = Self;
const EMPTY_COLLECTION_AS_KNOWN: KnownCollection<Self, T> =
KnownCollection::<Self, T>::from_variant(Self);
}
impl<T: Copy, const CAP: usize> KnownCollection<ArrayVec<T, CAP>, T> {
pub const fn from_variant(v: ArrayVec<T, CAP>) -> Self {
Self::ArrayVec(Yes, v)
}
}
impl<T: Copy, const CAP: usize> KnownCollection<LeadVec<T, CAP>, T> {
pub const fn from_variant(v: LeadVec<T, CAP>) -> Self {
Self::LeadVec(Yes, v)
}
}
impl<T: Copy> KnownCollection<Count, T> {
pub const fn from_variant(v: Count) -> Self {
Self::Count(Yes, v)
}
}
impl<T: Copy> KnownCollection<CollectNothing, T> {
pub const fn from_variant(v: CollectNothing) -> Self {
Self::CollectNothing(Yes, v)
}
}
impl<T: Copy, const CAP: usize> KnownCollection<ArrayVec<T, CAP>, T> {
pub const fn as_variant(&self) -> &ArrayVec<T, CAP> {
match self {
Self::ArrayVec(Yes, this) => this,
Self::LeadVec(no, _) => match *no {},
Self::Count(no, _) => match *no {},
Self::CollectNothing(no, _) => match *no {},
}
}
}
impl<T: Copy, const CAP: usize> KnownCollection<LeadVec<T, CAP>, T> {
pub const fn as_variant(&self) -> &LeadVec<T, CAP> {
match self {
Self::ArrayVec(no, _) => match *no {},
Self::LeadVec(Yes, this) => this,
Self::Count(no, _) => match *no {},
Self::CollectNothing(no, _) => match *no {},
}
}
}
impl<T: Copy> KnownCollection<Count, T> {
pub const fn as_variant(&self) -> &Count {
match self {
Self::ArrayVec(no, _) => match *no {},
Self::LeadVec(no, _) => match *no {},
Self::Count(Yes, this) => this,
Self::CollectNothing(no, _) => match *no {},
}
}
}
impl<T: Copy> KnownCollection<CollectNothing, T> {
pub const fn as_variant(&self) -> &CollectNothing {
match self {
Self::ArrayVec(no, _) => match *no {},
Self::LeadVec(no, _) => match *no {},
Self::Count(no, _) => match *no {},
Self::CollectNothing(Yes, this) => this,
}
}
}
impl<T: Copy> KnownCollection<CollectNothing, T> {
pub const fn into_variant(self) -> CollectNothing {
match self {
Self::ArrayVec(no, _) => match no {},
Self::LeadVec(no, _) => match no {},
Self::Count(no, _) => match no {},
Self::CollectNothing(Yes, this) => this,
}
}
}
impl<V, T: Copy, const ARRAY_VEC_CAP: usize, const LEAD_VEC_CAP: usize> KnownCollection<V, T>
where
V: IsKnownCollection<
T,
ArrayVecType = ArrayVec<T, ARRAY_VEC_CAP>,
LeadVecType = LeadVec<T, LEAD_VEC_CAP>,
>,
{
pub const fn with_push(self, value: T) -> Self
where
T: Copy,
{
match self {
KnownCollection::ArrayVec(y, this) => {
KnownCollection::ArrayVec(y, this.with_push(value))
}
KnownCollection::LeadVec(y, this) => KnownCollection::LeadVec(y, this.with_push(value)),
KnownCollection::Count(y, mut this) => KnownCollection::Count(y, {
this.len += 1;
this
}),
this @ KnownCollection::CollectNothing(_, _) => this,
}
}
pub const fn with_push_maybe_fake(self, value: T) -> (Self, Option<T>)
where
T: Copy,
{
match self {
KnownCollection::ArrayVec(y, this) => {
(KnownCollection::ArrayVec(y, this.with_push(value)), None)
}
KnownCollection::LeadVec(y, this) => {
let (this, value) = this.with_push_maybe_fake(value);
(KnownCollection::LeadVec(y, this), value)
}
KnownCollection::Count(y, mut this) => (
KnownCollection::Count(y, {
this.len += 1;
this
}),
Some(value),
),
this @ KnownCollection::CollectNothing(_, _) => (this, Some(value)),
}
}
}