1use 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#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
17pub struct True;
18
19#[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
31pub const ANYTHING: StaticStr = "anything";
33
34pub 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#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
55pub struct False;
56
57#[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
67pub const NOTHING: StaticStr = "nothing";
69
70pub 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#[derive(Debug)]
91pub enum EitherError<E, F> {
92 Left(E),
94 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#[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#[derive(Debug)]
166pub struct BothError<E, F> {
167 pub left: E,
169 pub right: F,
171}
172
173impl<E, F> BothError<E, F> {
174 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#[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#[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 pub const fn new() -> Self {
246 Self
247 }
248}
249
250#[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#[derive(Debug)]
277pub enum NeitherOrBoth<E, F> {
278 Neither,
280 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#[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
352pub type Nand<P, Q> = Not<And<P, Q>>;
354
355pub type Nor<P, Q> = Not<Or<P, Q>>;
357
358pub type Xnor<P, Q> = Not<Xor<P, Q>>;
360
361pub type Imply<P, Q> = Or<Not<P>, Q>;
363
364#[macro_export]
368macro_rules! not {
369 ($predicate: ty) => {
370 $crate::logic::Not<$predicate>
371 }
372}
373
374#[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#[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#[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}