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
15pub struct True {
17 private: PhantomData<()>,
18}
19
20#[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
32pub const ANYTHING: StaticStr = "anything";
34
35pub 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
54pub struct False {
56 private: PhantomData<()>,
57}
58
59#[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
69pub const NOTHING: StaticStr = "nothing";
71
72pub 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#[derive(Debug)]
93pub enum EitherError<E, F> {
94 Left(E),
96 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
136pub 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#[derive(Debug)]
167pub struct BothError<E, F> {
168 pub left: E,
170 pub right: F,
172}
173
174impl<E, F> BothError<E, F> {
175 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
205pub 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
250pub 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#[derive(Debug)]
276pub enum NeitherOrBoth<E, F> {
277 Neither,
279 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
319pub 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
350pub type Nand<P, Q> = Not<And<P, Q>>;
352
353pub type Nor<P, Q> = Not<Or<P, Q>>;
355
356pub type Xnor<P, Q> = Not<Xor<P, Q>>;
358
359pub type Imply<P, Q> = Or<Not<P>, Q>;
361
362#[macro_export]
366macro_rules! not {
367 ($predicate: ty) => {
368 $crate::logic::Not<$predicate>
369 }
370}
371
372#[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#[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#[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}