deke-types 1.1.1

Basse shared types for the Deke project.
Documentation
use std::{fmt::Debug, sync::Arc};

use crate::{DekeError, DekeResult, SRobotQ};

pub trait Validator<const N: usize>: Sized + Clone + Debug + Send + Sync + 'static {
    fn validate<E: Into<DekeError>, A: TryInto<SRobotQ<N>, Error = E>>(
        &mut self,
        q: A,
    ) -> DekeResult<()>;
    fn validate_motion(&mut self, qs: &[SRobotQ<N>]) -> DekeResult<()>;
}

#[derive(Debug, Clone)]
pub struct ValidatorAnd<A, B>(pub A, pub B);

#[derive(Debug, Clone)]
pub struct ValidatorOr<A, B>(pub A, pub B);

#[derive(Debug, Clone)]
pub struct ValidatorNot<A>(pub A);

impl<const N: usize, A, B> Validator<N> for ValidatorAnd<A, B>
where
    A: Validator<N>,
    B: Validator<N>,
{
    #[inline]
    fn validate<E: Into<DekeError>, Q: TryInto<SRobotQ<N>, Error = E>>(
        &mut self,
        q: Q,
    ) -> DekeResult<()> {
        let q = q.try_into().map_err(|e| e.into())?;
        self.0.validate(q)?;
        self.1.validate(q)
    }

    #[inline]
    fn validate_motion(&mut self, qs: &[SRobotQ<N>]) -> DekeResult<()> {
        self.0.validate_motion(qs)?;
        self.1.validate_motion(qs)
    }
}

impl<const N: usize, A, B> Validator<N> for ValidatorOr<A, B>
where
    A: Validator<N>,
    B: Validator<N>,
{
    #[inline]
    fn validate<E: Into<DekeError>, Q: TryInto<SRobotQ<N>, Error = E>>(
        &mut self,
        q: Q,
    ) -> DekeResult<()> {
        let q = q.try_into().map_err(|e| e.into())?;
        match self.0.validate(q) {
            Ok(()) => Ok(()),
            Err(_) => self.1.validate(q),
        }
    }

    #[inline]
    fn validate_motion(&mut self, qs: &[SRobotQ<N>]) -> DekeResult<()> {
        match self.0.validate_motion(qs) {
            Ok(()) => Ok(()),
            Err(_) => self.1.validate_motion(qs),
        }
    }
}

impl<const N: usize, A> Validator<N> for ValidatorNot<A>
where
    A: Validator<N>,
{
    #[inline]
    fn validate<E: Into<DekeError>, Q: TryInto<SRobotQ<N>, Error = E>>(
        &mut self,
        q: Q,
    ) -> DekeResult<()> {
        let q = q.try_into().map_err(|e| e.into())?;
        match self.0.validate(q) {
            Ok(()) => Err(DekeError::SuperError),
            Err(_) => Ok(()),
        }
    }

    #[inline]
    fn validate_motion(&mut self, qs: &[SRobotQ<N>]) -> DekeResult<()> {
        match self.0.validate_motion(qs) {
            Ok(()) => Err(DekeError::SuperError),
            Err(_) => Ok(()),
        }
    }
}

#[derive(Clone)]
pub struct JointValidator<const N: usize> {
    lower: SRobotQ<N>,
    upper: SRobotQ<N>,
    extras: Option<Arc<[Box<dyn Fn(&SRobotQ<N>) -> bool + Send + Sync>]>>,
}

impl<const N: usize> Debug for JointValidator<N> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("JointValidator")
            .field("lower", &self.lower)
            .field("upper", &self.upper)
            .field(
                "extras",
                &format!(
                    "[{} extra checks]",
                    self.extras.as_ref().map(|e| e.len()).unwrap_or(0)
                ),
            )
            .finish()
    }
}

impl<const N: usize> JointValidator<N> {
    pub fn new(lower: SRobotQ<N>, upper: SRobotQ<N>) -> Self {
        Self {
            lower,
            upper,
            extras: None,
        }
    }

    pub fn new_with_extras(
        lower: SRobotQ<N>,
        upper: SRobotQ<N>,
        extras: Vec<Box<dyn Fn(&SRobotQ<N>) -> bool + Send + Sync>>,
    ) -> Self {
        Self {
            lower,
            upper,
            extras: Some(extras.into()),
        }
    }
}

impl<const N: usize> Validator<N> for JointValidator<N> {
    #[inline]
    fn validate<E: Into<DekeError>, Q: TryInto<SRobotQ<N>, Error = E>>(
        &mut self,
        q: Q,
    ) -> DekeResult<()> {
        let q = q.try_into().map_err(|e| e.into())?;
        if q.any_lt(&self.lower) || q.any_gt(&self.upper) {
            return Err(DekeError::ExceedJointLimits);
        }
        if let Some(extras) = &self.extras {
            for check in extras.iter() {
                if !check(&q) {
                    return Err(DekeError::ExceedJointLimits);
                }
            }
        }
        Ok(())
    }

    #[inline]
    fn validate_motion(&mut self, qs: &[SRobotQ<N>]) -> DekeResult<()> {
        for q in qs {
            self.validate(*q)?;
        }
        Ok(())
    }
}