openpql-range-parser 0.1.0

Poker Range Notation Parser
Documentation
use super::{
    Array, Card, Constrain, Error, Idx, LocInfo, ast, range_cond_indices,
};

#[derive(PartialEq, Eq, Debug, Clone)]
pub(super) struct Leaf<const N: usize, const B: bool>
where
    [Idx; N]: Array<Item = Idx>,
{
    constrains: [Constrain<N>; N],
}

impl<const N: usize, const B: bool> Leaf<N, B>
where
    [Idx; N]: Array<Item = Idx>,
{
    pub const fn new(constrains: [Constrain<N>; N]) -> Self {
        Self { constrains }
    }

    #[inline]
    pub fn is_satisfied(&self, cs: &[Card]) -> bool {
        let n = self.constrains.len();
        let r = cs.len();

        !range_cond_indices(n, r, B)
            .iter()
            .all(|perm| Constrain::reject(&self.constrains, cs, perm))
    }
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Deps(pub LocInfo);

impl<const N: usize, const B: bool> TryFrom<(ast::Term, Deps)> for Leaf<N, B>
where
    [Idx; N]: Array<Item = Idx>,
{
    type Error = Error;

    fn try_from((term, deps): (ast::Term, Deps)) -> Result<Self, Self::Error> {
        let mut constrains = vec![];
        let mut i = 0;

        for el in &term.0 {
            match el {
                ast::TermElem::Card(c) => {
                    constrains.push(Constrain::from_card(&term, *c, i));
                    i += 1;
                }

                ast::TermElem::List(l) => {
                    constrains.push(Constrain::from_list(l));
                    i += 1;
                }

                ast::TermElem::Span(s) => {
                    let v = Constrain::from_span(s, i);

                    i += v.len().to_le_bytes()[0];

                    constrains.extend(v);
                }
            }
        }

        if i as usize > N {
            Err(Error::TooManyCardsInRange(deps.0))
        } else {
            for _ in i as usize..N {
                constrains.push(Constrain::default());
            }

            Ok(Self::new(constrains.try_into().unwrap()))
        }
    }
}