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