use crate::grammar::Grammar;
use std::marker::PhantomData;
pub trait First {
#[doc(hidden)]
type Concat<G: Grammar>: First;
#[doc(hidden)]
type Union<X: First>: First;
#[doc(hidden)]
type UnionByteSet<X: ByteSet>: First;
type Nullable: First;
type WithChar<const C: char>: First;
type WithCharCI<const C: char>: First;
#[doc(hidden)]
const CONTAINS_BYTE: [bool; 256];
#[doc(hidden)]
const CONTAINS_NIL: bool;
}
#[doc(hidden)]
pub trait ByteSet: First {}
pub struct Never;
impl ByteSet for Never {}
impl First for Never {
type Concat<G: Grammar> = Self;
type Union<X: First> = X;
type UnionByteSet<X: ByteSet> = X;
type Nullable = OptionalFirst<Self>;
type WithChar<const D: char> = AddChar<Self, D>;
type WithCharCI<const D: char> = AddCharCI<Self, D>;
const CONTAINS_BYTE: [bool; 256] = [false; 256];
const CONTAINS_NIL: bool = false;
}
pub struct AnyChar;
impl ByteSet for AnyChar {}
impl First for AnyChar {
type Concat<G: Grammar> = Self;
type Union<X: First> = X::UnionByteSet<Self>;
type UnionByteSet<X: ByteSet> = Self;
type Nullable = OptionalFirst<Self>;
type WithChar<const D: char> = AddChar<Self, D>;
type WithCharCI<const D: char> = AddCharCI<Self, D>;
const CONTAINS_BYTE: [bool; 256] = [true; 256];
const CONTAINS_NIL: bool = false;
}
#[doc(hidden)]
pub struct AddChar<B: ByteSet, const C: char>(PhantomData<B>);
impl<B: ByteSet, const C: char> ByteSet for AddChar<B, C> {}
impl<B: ByteSet, const C: char> First for AddChar<B, C> {
type Concat<G: Grammar> = Self;
type Union<X: First> = X::UnionByteSet<Self>;
type UnionByteSet<X: ByteSet> = UnionSet<Self, X>;
type Nullable = OptionalFirst<Self>;
type WithChar<const D: char> = AddChar<Self, D>;
type WithCharCI<const D: char> = AddCharCI<Self, D>;
const CONTAINS_BYTE: [bool; 256] = {
let mut map = B::CONTAINS_BYTE;
map[first_byte(C) as usize] = true;
map
};
const CONTAINS_NIL: bool = false;
}
const fn first_byte(c: char) -> u8 {
let mut buf = [0u8; 4];
c.encode_utf8(&mut buf);
buf[0]
}
#[doc(hidden)]
pub struct AddCharCI<B: ByteSet, const C: char>(PhantomData<B>);
impl<B: ByteSet, const C: char> ByteSet for AddCharCI<B, C> {}
impl<B: ByteSet, const C: char> First for AddCharCI<B, C> {
type Concat<G: Grammar> = Self;
type Union<X: First> = X::UnionByteSet<Self>;
type UnionByteSet<X: ByteSet> = UnionSet<Self, X>;
type Nullable = OptionalFirst<Self>;
type WithChar<const D: char> = AddChar<Self, D>;
type WithCharCI<const D: char> = AddCharCI<Self, D>;
const CONTAINS_BYTE: [bool; 256] = {
let mut map = B::CONTAINS_BYTE;
map[first_byte(C.to_ascii_lowercase()) as usize] = true;
map[first_byte(C.to_ascii_uppercase()) as usize] = true;
map
};
const CONTAINS_NIL: bool = false;
}
#[doc(hidden)]
pub struct UnionSet<A: ByteSet, B: ByteSet>(PhantomData<(A, B)>);
impl<A: ByteSet, B: ByteSet> ByteSet for UnionSet<A, B> {}
impl<A: ByteSet, B: ByteSet> First for UnionSet<A, B> {
type Concat<G: Grammar> = Self;
type Union<X: First> = X::UnionByteSet<Self>;
type UnionByteSet<X: ByteSet> = UnionSet<Self, X>;
type Nullable = OptionalFirst<Self>;
type WithChar<const D: char> = AddChar<Self, D>;
type WithCharCI<const D: char> = AddCharCI<Self, D>;
const CONTAINS_BYTE: [bool; 256] = {
let a = A::CONTAINS_BYTE;
let b = B::CONTAINS_BYTE;
let mut map = [false; 256];
let mut i = 0;
while i < 256 {
map[i] = a[i] || b[i];
i += 1;
}
map
};
const CONTAINS_NIL: bool = false;
}
pub(crate) type CharFirst<const C: char> = AddChar<Never, C>;
pub(crate) type CharFirstCI<const C: char> = AddCharCI<Never, C>;
#[doc(hidden)]
pub struct OptionalFirst<B: ByteSet>(PhantomData<B>);
impl<B: ByteSet> First for OptionalFirst<B> {
type Concat<G: Grammar> = <B as First>::Union<G::First>;
type Union<X: First> = <X::UnionByteSet<B> as First>::Nullable;
type UnionByteSet<X: ByteSet> = <B::UnionByteSet<X> as First>::Nullable;
type Nullable = Self;
type WithChar<const D: char> = <B::WithChar<D> as First>::Nullable;
type WithCharCI<const D: char> = <B::WithCharCI<D> as First>::Nullable;
const CONTAINS_BYTE: [bool; 256] = B::CONTAINS_BYTE;
const CONTAINS_NIL: bool = true;
}
pub(crate) type EmptyFirst = OptionalFirst<Never>;