Skip to main content

deke_types/
validator.rs

1use std::{fmt::Debug, sync::Arc};
2
3use crate::{DekeError, DekeResult, SRobotQ, SRobotQLike};
4
5
6pub trait ValidatorContext: Sized {}
7
8#[doc(hidden)]
9pub trait Leaf: ValidatorContext {}
10
11impl ValidatorContext for () {}
12
13#[macro_export]
14macro_rules! validator_context_type_impl {
15    ($($ident:ident),*) => {
16        $(
17            impl $crate::ValidatorContext for $ident {}
18            impl $crate::Leaf for $ident {}
19        )*
20    };
21}
22
23impl<A: ValidatorContext, B: ValidatorContext> ValidatorContext for (A, B) {}
24
25pub trait FromFlattened<Flattened>: ValidatorContext {
26    fn nest(flattened: Flattened) -> Self;
27}
28
29macro_rules! validator_context_tuple_impl {
30    ($tup:tt) => {
31        validator_context_tuple_impl!(@rewrite $tup [emit_impl]);
32    };
33
34    (@rewrite ($l:tt, $r:tt) [$($cb:tt)*]) => {
35        validator_context_tuple_impl!(@rewrite $l [pair_right $r [$($cb)*]]);
36    };
37    (@rewrite $ident:ident [$($cb:tt)*]) => {
38        validator_context_tuple_impl!(@invoke [$($cb)*] [$ident] $ident);
39        validator_context_tuple_impl!(@invoke [$($cb)*] [] ());
40    };
41
42    (@invoke [pair_right $r:tt [$($cb:tt)*]] [$($kept_l:ident)*] $rew_l:tt) => {
43        validator_context_tuple_impl!(@rewrite $r [pair_combine [$($kept_l)*] $rew_l [$($cb)*]]);
44    };
45    (@invoke [pair_combine [$($kept_l:ident)*] $rew_l:tt [$($cb:tt)*]] [$($kept_r:ident)*] $rew_r:tt) => {
46        validator_context_tuple_impl!(@invoke [$($cb)*] [$($kept_l)* $($kept_r)*] ($rew_l, $rew_r));
47    };
48    (@invoke [emit_impl] [$($kept:ident)*] $shape:tt) => {
49        #[allow(non_snake_case)]
50        impl<$($kept: Leaf),*> FromFlattened<($($kept,)*)> for $shape {
51            #[inline]
52            fn nest(flattened: ($($kept,)*)) -> Self {
53                let ($($kept,)*) = flattened;
54                $shape
55            }
56        }
57    };
58}
59
60validator_context_tuple_impl! { (A, (B, C)) }
61validator_context_tuple_impl! { ((A, B), C) }
62
63validator_context_tuple_impl! { (A, (B, (C, D))) }
64validator_context_tuple_impl! { (A, ((B, C), D)) }
65validator_context_tuple_impl! { ((A, B), (C, D)) }
66validator_context_tuple_impl! { ((A, (B, C)), D) }
67validator_context_tuple_impl! { (((A, B), C), D) }
68
69validator_context_tuple_impl! { (A, (B, (C, (D, E)))) }
70validator_context_tuple_impl! { (A, (B, ((C, D), E))) }
71validator_context_tuple_impl! { (A, ((B, C), (D, E))) }
72validator_context_tuple_impl! { (A, ((B, (C, D)), E)) }
73validator_context_tuple_impl! { (A, (((B, C), D), E)) }
74validator_context_tuple_impl! { ((A, B), (C, (D, E))) }
75validator_context_tuple_impl! { ((A, B), ((C, D), E)) }
76validator_context_tuple_impl! { ((A, (B, C)), (D, E)) }
77validator_context_tuple_impl! { (((A, B), C), (D, E)) }
78validator_context_tuple_impl! { ((A, (B, (C, D))), E) }
79validator_context_tuple_impl! { ((A, ((B, C), D)), E) }
80validator_context_tuple_impl! { (((A, B), (C, D)), E) }
81validator_context_tuple_impl! { (((A, (B, C)), D), E) }
82validator_context_tuple_impl! { ((((A, B), C), D), E) }
83
84validator_context_tuple_impl! { ((A, B), ((C, D), (E, F))) }
85validator_context_tuple_impl! { (((A, B), (C, D)), (E, F)) }
86validator_context_tuple_impl! { ((A, (B, C)), ((D, E), F)) }
87validator_context_tuple_impl! { (((A, B), C), ((D, E), F)) }
88
89pub trait Validator<const N: usize>: Sized + Clone + Debug + Send + Sync + 'static {
90    type Context<'ctx>: ValidatorContext;
91
92    fn validate<'ctx, E: Into<DekeError>, A: SRobotQLike<N, E>>(
93        &mut self,
94        q: A,
95        ctx: &Self::Context<'ctx>,
96    ) -> DekeResult<()>;
97    fn validate_motion<'ctx>(
98        &mut self,
99        qs: &[SRobotQ<N>],
100        ctx: &Self::Context<'ctx>,
101    ) -> DekeResult<()>;
102}
103
104#[derive(Debug, Clone)]
105pub struct ValidatorAnd<A, B>(pub A, pub B);
106
107#[derive(Debug, Clone)]
108pub struct ValidatorOr<A, B>(pub A, pub B);
109
110#[derive(Debug, Clone)]
111pub struct ValidatorNot<A>(pub A);
112
113impl<const N: usize, A, B> Validator<N> for ValidatorAnd<A, B>
114where
115    A: Validator<N>,
116    B: Validator<N>,
117{
118    type Context<'ctx> = (A::Context<'ctx>, B::Context<'ctx>);
119
120    #[inline]
121    fn validate<'ctx, E: Into<DekeError>, Q: SRobotQLike<N, E>>(
122        &mut self,
123        q: Q,
124        ctx: &Self::Context<'ctx>,
125    ) -> DekeResult<()> {
126        let q = q.to_srobotq().map_err(Into::into)?;
127        self.0.validate(q, &ctx.0)?;
128        self.1.validate(q, &ctx.1)
129    }
130
131    #[inline]
132    fn validate_motion<'ctx>(
133        &mut self,
134        qs: &[SRobotQ<N>],
135        ctx: &Self::Context<'ctx>,
136    ) -> DekeResult<()> {
137        self.0.validate_motion(qs, &ctx.0)?;
138        self.1.validate_motion(qs, &ctx.1)
139    }
140}
141
142impl<const N: usize, A, B> Validator<N> for ValidatorOr<A, B>
143where
144    A: Validator<N>,
145    B: Validator<N>,
146{
147    type Context<'ctx> = (A::Context<'ctx>, B::Context<'ctx>);
148
149    #[inline]
150    fn validate<'ctx, E: Into<DekeError>, Q: SRobotQLike<N, E>>(
151        &mut self,
152        q: Q,
153        ctx: &Self::Context<'ctx>,
154    ) -> DekeResult<()> {
155        let q = q.to_srobotq().map_err(Into::into)?;
156        match self.0.validate(q, &ctx.0) {
157            Ok(()) => Ok(()),
158            Err(_) => self.1.validate(q, &ctx.1),
159        }
160    }
161
162    #[inline]
163    fn validate_motion<'ctx>(
164        &mut self,
165        qs: &[SRobotQ<N>],
166        ctx: &Self::Context<'ctx>,
167    ) -> DekeResult<()> {
168        match self.0.validate_motion(qs, &ctx.0) {
169            Ok(()) => Ok(()),
170            Err(_) => self.1.validate_motion(qs, &ctx.1),
171        }
172    }
173}
174
175impl<const N: usize, A> Validator<N> for ValidatorNot<A>
176where
177    A: Validator<N>,
178{
179    type Context<'ctx> = A::Context<'ctx>;
180
181    #[inline]
182    fn validate<'ctx, E: Into<DekeError>, Q: SRobotQLike<N, E>>(
183        &mut self,
184        q: Q,
185        ctx: &Self::Context<'ctx>,
186    ) -> DekeResult<()> {
187        let q = q.to_srobotq().map_err(Into::into)?;
188        match self.0.validate(q, ctx) {
189            Ok(()) => Err(DekeError::SuperError),
190            Err(_) => Ok(()),
191        }
192    }
193
194    #[inline]
195    fn validate_motion<'ctx>(
196        &mut self,
197        qs: &[SRobotQ<N>],
198        ctx: &Self::Context<'ctx>,
199    ) -> DekeResult<()> {
200        match self.0.validate_motion(qs, ctx) {
201            Ok(()) => Err(DekeError::SuperError),
202            Err(_) => Ok(()),
203        }
204    }
205}
206
207#[derive(Clone)]
208pub struct JointValidator<const N: usize> {
209    lower: SRobotQ<N>,
210    upper: SRobotQ<N>,
211    extras: Option<Arc<[Box<dyn Fn(&SRobotQ<N>) -> bool + Send + Sync>]>>,
212}
213
214impl<const N: usize> Debug for JointValidator<N> {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        f.debug_struct("JointValidator")
217            .field("lower", &self.lower)
218            .field("upper", &self.upper)
219            .field(
220                "extras",
221                &format!(
222                    "[{} extra checks]",
223                    self.extras.as_ref().map(|e| e.len()).unwrap_or(0)
224                ),
225            )
226            .finish()
227    }
228}
229
230impl<const N: usize> JointValidator<N> {
231    pub fn new(lower: SRobotQ<N>, upper: SRobotQ<N>) -> Self {
232        Self {
233            lower,
234            upper,
235            extras: None,
236        }
237    }
238
239    pub fn new_with_extras(
240        lower: SRobotQ<N>,
241        upper: SRobotQ<N>,
242        extras: Vec<Box<dyn Fn(&SRobotQ<N>) -> bool + Send + Sync>>,
243    ) -> Self {
244        Self {
245            lower,
246            upper,
247            extras: Some(extras.into()),
248        }
249    }
250}
251
252impl<const N: usize> Validator<N> for JointValidator<N> {
253    type Context<'ctx> = ();
254
255    #[inline]
256    fn validate<'ctx, E: Into<DekeError>, Q: SRobotQLike<N, E>>(
257        &mut self,
258        q: Q,
259        _ctx: &Self::Context<'ctx>,
260    ) -> DekeResult<()> {
261        let q = q.to_srobotq().map_err(Into::into)?;
262        if q.any_lt(&self.lower) || q.any_gt(&self.upper) {
263            return Err(DekeError::ExceedJointLimits);
264        }
265        if let Some(extras) = &self.extras {
266            for check in extras.iter() {
267                if !check(&q) {
268                    return Err(DekeError::ExceedJointLimits);
269                }
270            }
271        }
272        Ok(())
273    }
274
275    #[inline]
276    fn validate_motion<'ctx>(
277        &mut self,
278        qs: &[SRobotQ<N>],
279        _ctx: &Self::Context<'ctx>,
280    ) -> DekeResult<()> {
281        for q in qs {
282            self.validate(*q, _ctx)?;
283        }
284        Ok(())
285    }
286}