refinement_types/
logic.rs

1//! Logical operations on predicates.
2
3use core::{fmt, marker::PhantomData};
4
5use thiserror::Error;
6
7use crate::{core::Predicate, static_str::StaticStr};
8
9/// Represents predicates that are always satisfied.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
11pub struct True;
12
13/// Represents errors that are never encountered.
14///
15/// This is essentially `!`, the never type.
16#[derive(Debug, Error)]
17pub enum NeverError {}
18
19/// The `anything` string.
20pub const ANYTHING: StaticStr = "anything";
21
22impl<T: ?Sized> Predicate<T> for True {
23    type Error = NeverError;
24
25    fn check(_value: &T) -> Result<(), Self::Error> {
26        Ok(())
27    }
28
29    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
30        formatter.write_str(ANYTHING)
31    }
32}
33
34/// Represents predicates that are never satisfied (`0`).
35#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
36pub struct False;
37
38/// Represents errors that are always encountered.
39#[derive(Debug, Error)]
40#[error("always errors")]
41pub struct AlwaysError;
42
43/// The `nothing` string.
44pub const NOTHING: StaticStr = "nothing";
45
46impl<T: ?Sized> Predicate<T> for False {
47    type Error = AlwaysError;
48
49    fn check(_value: &T) -> Result<(), Self::Error> {
50        Err(AlwaysError)
51    }
52
53    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
54        formatter.write_str(NOTHING)
55    }
56}
57
58/// Represents errors returned by [`And`].
59#[derive(Debug, Error)]
60pub enum EitherError<E, F> {
61    /// Left error (`P` failed).
62    #[error("left error: {0}")]
63    Left(E),
64    /// Right error (`Q` failed).
65    #[error("right error: {0}")]
66    Right(F),
67}
68
69/// Represents predicates that are satisfied when both `P` and `Q` are satisfied.
70#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
71pub struct And<P: ?Sized, Q: ?Sized> {
72    left: PhantomData<P>,
73    right: PhantomData<Q>,
74}
75
76impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for And<P, Q> {
77    type Error = EitherError<P::Error, Q::Error>;
78
79    fn check(value: &T) -> Result<(), Self::Error> {
80        P::check(value)
81            .map_err(EitherError::Left)
82            .and_then(|()| Q::check(value).map_err(EitherError::Right))
83    }
84
85    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
86        write!(formatter, "({}) and ({})", P::expected(), Q::expected())
87    }
88}
89
90/// Represents errors returned by [`Or`].
91#[derive(Debug, Error)]
92#[error("both errors encountered: {left} and {right}")]
93pub struct BothError<E, F> {
94    /// Left error (`P` failed).
95    pub left: E,
96    /// Right error (`Q` failed).
97    pub right: F,
98}
99
100impl<E, F> BothError<E, F> {
101    /// Constructs [`Self`]
102    pub const fn new(left: E, right: F) -> Self {
103        Self { left, right }
104    }
105}
106
107/// Represents predicates that are satisfied when either `P` or `Q` (or both) are satisfied.
108#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
109pub struct Or<P: ?Sized, Q: ?Sized> {
110    left: PhantomData<P>,
111    right: PhantomData<Q>,
112}
113
114impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for Or<P, Q> {
115    type Error = BothError<P::Error, Q::Error>;
116
117    fn check(value: &T) -> Result<(), Self::Error> {
118        P::check(value)
119            .or_else(|left| Q::check(value).map_err(|right| Self::Error::new(left, right)))
120    }
121
122    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
123        write!(formatter, "({}) or ({})", P::expected(), Q::expected())
124    }
125}
126
127/// Represents errors returned by [`Not`].
128#[derive(Debug, Error)]
129#[error("negated error")]
130pub struct NotError;
131
132/// Represents predicates that are satisfied when `P` is not satisfied.
133#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
134pub struct Not<P: ?Sized> {
135    predicate: PhantomData<P>,
136}
137
138impl<T: ?Sized, P: Predicate<T> + ?Sized> Predicate<T> for Not<P> {
139    type Error = NotError;
140
141    fn check(value: &T) -> Result<(), Self::Error> {
142        match P::check(value) {
143            Ok(()) => Err(NotError),
144            Err(_) => Ok(()),
145        }
146    }
147
148    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
149        write!(formatter, "not ({})", P::expected())
150    }
151}
152
153/// Represents errors returned by [`Xor`].
154#[derive(Debug, Error)]
155pub enum NeitherOrBoth<E, F> {
156    /// Neither error encountered.
157    #[error("neither error encountered")]
158    Neither,
159    /// Both errors encountered.
160    #[error(transparent)]
161    Both(BothError<E, F>),
162}
163
164/// Represents predicates that are satisfied when either `P` or `Q` (but *not* both) are satisfied.
165#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
166pub struct Xor<P: ?Sized, Q: ?Sized> {
167    left: PhantomData<P>,
168    right: PhantomData<Q>,
169}
170
171impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for Xor<P, Q> {
172    type Error = NeitherOrBoth<P::Error, Q::Error>;
173
174    fn check(value: &T) -> Result<(), Self::Error> {
175        match (P::check(value), Q::check(value)) {
176            (Ok(()), Ok(())) => Err(NeitherOrBoth::Neither),
177            (Err(left), Err(right)) => Err(NeitherOrBoth::Both(BothError::new(left, right))),
178            _ => Ok(()),
179        }
180    }
181
182    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
183        write!(formatter, "({}) xor ({})", P::expected(), Q::expected())
184    }
185}
186
187/// Composes [`Not`] and [`And`].
188pub type Nand<P, Q> = Not<And<P, Q>>;
189/// Composes [`Not`] and [`Or`].
190pub type Nor<P, Q> = Not<Or<P, Q>>;
191/// Composes [`Not`] and [`Xor`].
192pub type Xnor<P, Q> = Not<Xor<P, Q>>;
193
194/// Represents predicates that are satisfied when `P` implies `Q`.
195pub type Imply<P, Q> = Or<Not<P>, Q>;