refinement_types/
logic.rs

1//! Logical operations on predicates.
2
3use core::{fmt, marker::PhantomData};
4
5#[cfg(feature = "diagnostics")]
6use miette::Diagnostic;
7
8use thiserror::Error;
9
10use crate::{
11    core::{ErrorCore, Predicate},
12    static_str::StaticStr,
13};
14
15/// Represents predicates that are always satisfied.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
17pub struct True;
18
19/// Represents errors that are never encountered.
20///
21/// This is essentially `!`, the never type.
22#[derive(Debug, Error)]
23#[error("never errors")]
24#[cfg_attr(
25    feature = "diagnostics",
26    derive(Diagnostic),
27    diagnostic(code(logic::never), help("this error is never returned"))
28)]
29pub enum NeverError {}
30
31/// The `anything` string.
32pub const ANYTHING: StaticStr = "anything";
33
34/// The `true` string.
35pub const TRUE: StaticStr = "true";
36
37impl<T: ?Sized> Predicate<T> for True {
38    type Error = NeverError;
39
40    fn check(_value: &T) -> Result<(), Self::Error> {
41        Ok(())
42    }
43
44    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
45        formatter.write_str(ANYTHING)
46    }
47
48    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
49        formatter.write_str(TRUE)
50    }
51}
52
53/// Represents predicates that are never satisfied.
54#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
55pub struct False;
56
57/// Represents errors that are always encountered.
58#[derive(Debug, Error)]
59#[error("always errors")]
60#[cfg_attr(
61    feature = "diagnostics",
62    derive(Diagnostic),
63    diagnostic(code(logic::always), help("this error is always returned"))
64)]
65pub struct AlwaysError;
66
67/// The `nothing` string.
68pub const NOTHING: StaticStr = "nothing";
69
70/// The `false` string.
71pub const FALSE: StaticStr = "false";
72
73impl<T: ?Sized> Predicate<T> for False {
74    type Error = AlwaysError;
75
76    fn check(_value: &T) -> Result<(), Self::Error> {
77        Err(AlwaysError)
78    }
79
80    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
81        formatter.write_str(NOTHING)
82    }
83
84    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
85        formatter.write_str(FALSE)
86    }
87}
88
89/// Represents errors returned by [`And`].
90#[derive(Debug)]
91pub enum EitherError<E, F> {
92    /// Left error (`P` failed).
93    Left(E),
94    /// Right error (`Q` failed).
95    Right(F),
96}
97
98impl<E: fmt::Display, F: fmt::Display> fmt::Display for EitherError<E, F> {
99    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
100        match self {
101            Self::Left(left) => write!(formatter, "left error: {left}"),
102            Self::Right(right) => write!(formatter, "right error: {right}"),
103        }
104    }
105}
106
107impl<E: ErrorCore + 'static, F: ErrorCore + 'static> ErrorCore for EitherError<E, F> {
108    fn source(&self) -> Option<&(dyn ErrorCore + 'static)> {
109        match self {
110            Self::Left(left) => Some(left),
111            Self::Right(right) => Some(right),
112        }
113    }
114}
115
116#[cfg(feature = "diagnostics")]
117impl<E: Diagnostic + 'static, F: Diagnostic + 'static> Diagnostic for EitherError<E, F> {
118    fn code(&self) -> Option<Box<dyn fmt::Display + '_>> {
119        Some(Box::new("logic::either"))
120    }
121
122    fn help(&self) -> Option<Box<dyn fmt::Display + '_>> {
123        Some(Box::new("make sure both predicates are satisfied"))
124    }
125
126    fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
127        match self {
128            Self::Left(left) => Some(left),
129            Self::Right(right) => Some(right),
130        }
131    }
132}
133
134/// Represents predicates that are satisfied when both `P` and `Q` are satisfied.
135#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
136pub struct And<P: ?Sized, Q: ?Sized> {
137    left: PhantomData<P>,
138    right: PhantomData<Q>,
139}
140
141impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for And<P, Q> {
142    type Error = EitherError<P::Error, Q::Error>;
143
144    fn check(value: &T) -> Result<(), Self::Error> {
145        P::check(value)
146            .map_err(EitherError::Left)
147            .and_then(|()| Q::check(value).map_err(EitherError::Right))
148    }
149
150    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
151        write!(formatter, "({}) and ({})", P::expected(), Q::expected())
152    }
153
154    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
155        write!(
156            formatter,
157            "and<{}, {}>",
158            P::expected_code(),
159            Q::expected_code()
160        )
161    }
162}
163
164/// Represents errors returned by [`Or`].
165#[derive(Debug)]
166pub struct BothError<E, F> {
167    /// Left error (`P` failed).
168    pub left: E,
169    /// Right error (`Q` failed).
170    pub right: F,
171}
172
173impl<E, F> BothError<E, F> {
174    /// Constructs [`Self`].
175    pub const fn new(left: E, right: F) -> Self {
176        Self { left, right }
177    }
178}
179
180impl<E: fmt::Display, F: fmt::Display> fmt::Display for BothError<E, F> {
181    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
182        write!(
183            formatter,
184            "both errors occured: {left} and {right}",
185            left = self.left,
186            right = self.right
187        )
188    }
189}
190
191impl<E: ErrorCore, F: ErrorCore> ErrorCore for BothError<E, F> {}
192
193#[cfg(feature = "diagnostics")]
194impl<E: Diagnostic, F: Diagnostic> Diagnostic for BothError<E, F> {
195    fn code(&self) -> Option<Box<dyn fmt::Display + '_>> {
196        Some(Box::new("logic::both"))
197    }
198
199    fn help(&self) -> Option<Box<dyn fmt::Display + '_>> {
200        Some(Box::new("make sure at least one predicate is satisfied"))
201    }
202}
203
204/// Represents predicates that are satisfied when either `P` or `Q` (or both) are satisfied.
205#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
206pub struct Or<P: ?Sized, Q: ?Sized> {
207    left: PhantomData<P>,
208    right: PhantomData<Q>,
209}
210
211impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for Or<P, Q> {
212    type Error = BothError<P::Error, Q::Error>;
213
214    fn check(value: &T) -> Result<(), Self::Error> {
215        P::check(value)
216            .or_else(|left| Q::check(value).map_err(|right| Self::Error::new(left, right)))
217    }
218
219    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
220        write!(formatter, "({}) or ({})", P::expected(), Q::expected())
221    }
222
223    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
224        write!(
225            formatter,
226            "or<{}, {}>",
227            P::expected_code(),
228            Q::expected_code()
229        )
230    }
231}
232
233/// Represents errors returned by [`Not`].
234#[derive(Debug, Error, Default)]
235#[error("negated error")]
236#[cfg_attr(
237    feature = "diagnostics",
238    derive(Diagnostic),
239    diagnostic(code(logic::not), help("make sure the negated predicate is satisfied"))
240)]
241pub struct NotError;
242
243impl NotError {
244    /// Constructs [`Self`].
245    pub const fn new() -> Self {
246        Self
247    }
248}
249
250/// Represents predicates that are satisfied when `P` is not satisfied.
251#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
252pub struct Not<P: ?Sized> {
253    predicate: PhantomData<P>,
254}
255
256impl<T: ?Sized, P: Predicate<T> + ?Sized> Predicate<T> for Not<P> {
257    type Error = NotError;
258
259    fn check(value: &T) -> Result<(), Self::Error> {
260        match P::check(value) {
261            Ok(()) => Err(Self::Error::new()),
262            Err(_) => Ok(()),
263        }
264    }
265
266    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
267        write!(formatter, "not ({})", P::expected())
268    }
269
270    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
271        write!(formatter, "not<{}>", P::expected_code())
272    }
273}
274
275/// Represents errors returned by [`Xor`].
276#[derive(Debug)]
277pub enum NeitherOrBoth<E, F> {
278    /// Neither error encountered.
279    Neither,
280    /// Both errors encountered.
281    Both(BothError<E, F>),
282}
283
284impl<E: fmt::Display, F: fmt::Display> fmt::Display for NeitherOrBoth<E, F> {
285    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
286        match self {
287            Self::Neither => formatter.write_str("neither error encountered"),
288            Self::Both(both) => both.fmt(formatter),
289        }
290    }
291}
292
293impl<E: ErrorCore + 'static, F: ErrorCore + 'static> ErrorCore for NeitherOrBoth<E, F> {
294    fn source(&self) -> Option<&(dyn ErrorCore + 'static)> {
295        match self {
296            Self::Neither => None,
297            Self::Both(both) => Some(both),
298        }
299    }
300}
301
302#[cfg(feature = "diagnostics")]
303impl<E: Diagnostic + 'static, F: Diagnostic + 'static> Diagnostic for NeitherOrBoth<E, F> {
304    fn code(&self) -> Option<Box<dyn fmt::Display + '_>> {
305        Some(Box::new("logic::neither_or_both"))
306    }
307
308    fn help(&self) -> Option<Box<dyn fmt::Display + '_>> {
309        Some(Box::new("make sure only one predicate is satisfied"))
310    }
311
312    fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
313        match self {
314            Self::Neither => None,
315            Self::Both(both) => Some(both),
316        }
317    }
318}
319
320/// Represents predicates that are satisfied when either `P` or `Q` (but *not* both) are satisfied.
321#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
322pub struct Xor<P: ?Sized, Q: ?Sized> {
323    left: PhantomData<P>,
324    right: PhantomData<Q>,
325}
326
327impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for Xor<P, Q> {
328    type Error = NeitherOrBoth<P::Error, Q::Error>;
329
330    fn check(value: &T) -> Result<(), Self::Error> {
331        match (P::check(value), Q::check(value)) {
332            (Ok(()), Ok(())) => Err(NeitherOrBoth::Neither),
333            (Err(left), Err(right)) => Err(NeitherOrBoth::Both(BothError::new(left, right))),
334            _ => Ok(()),
335        }
336    }
337
338    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
339        write!(formatter, "({}) xor ({})", P::expected(), Q::expected())
340    }
341
342    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
343        write!(
344            formatter,
345            "xor<{}, {}>",
346            P::expected_code(),
347            Q::expected_code()
348        )
349    }
350}
351
352/// Composes [`Not`] and [`And`].
353pub type Nand<P, Q> = Not<And<P, Q>>;
354
355/// Composes [`Not`] and [`Or`].
356pub type Nor<P, Q> = Not<Or<P, Q>>;
357
358/// Composes [`Not`] and [`Xor`].
359pub type Xnor<P, Q> = Not<Xor<P, Q>>;
360
361/// Represents predicates that are satisfied when `P` implies `Q`.
362pub type Imply<P, Q> = Or<Not<P>, Q>;
363
364/// Negates the given predicate.
365///
366/// For predicate `P`, `not!(P)` is [`Not<P>`].
367#[macro_export]
368macro_rules! not {
369    ($predicate: ty) => {
370        $crate::logic::Not<$predicate>
371    }
372}
373
374/// Given two or more predicates, composes them together with [`And`].
375///
376/// For predicates `P` and `Q`, `and!(P, Q)` is [`And<P, Q>`].
377///
378/// For predicates `P`, `Q`, and `R`, `and!(P, Q, R)` is [`And<P, And<Q, R>>`].
379///
380/// Ad infinitum...
381#[macro_export]
382macro_rules! and {
383    ($first: ty, $second: ty) => {
384        $crate::logic::And<$first, $second>
385    };
386
387    ($first: ty, $second: ty, $($rest: ty),+ $(,)?) => {
388        $crate::and!($first, $crate::and!($second, $($rest),+))
389    }
390}
391
392/// Given two or more predicates, composes them together with [`Or`].
393///
394/// For predicates `P` and `Q`, `or!(P, Q)` is [`Or<P, Q>`].
395///
396/// For predicates `P`, `Q`, and `R`, `or!(P, Q, R)` is [`Or<P, Or<Q, R>>`].
397///
398/// Ad infinitum...
399#[macro_export]
400macro_rules! or {
401    ($first: ty, $second: ty) => {
402        $crate::logic::Or<$first, $second>
403    };
404
405    ($first: ty, $second: ty, $($rest: ty),+ $(,)?) => {
406        $crate::or!($first, $crate::or!($second, $($rest),+))
407    }
408}
409
410/// Given two or more predicates, composes them together with [`Xor`].
411///
412/// For predicates `P` and `Q`, `xor!(P, Q)` is [`Xor<P, Q>`].
413///
414/// For predicates `P`, `Q`, and `R`, `xor!(P, Q, R)` is [`Xor<P, Xor<Q, R>>`].
415///
416/// Ad infinitum...
417#[macro_export]
418macro_rules! xor {
419    ($first: ty, $second: ty) => {
420        $crate::logic::Xor<$first, $second>
421    };
422
423    ($first: ty, $second: ty, $($rest: ty),+ $(,)?) => {
424        $crate::xor!($first, $crate::xor!($second, $($rest),+))
425    }
426}