|
| 1 | +//! Crate error types. |
| 2 | +
|
| 3 | +use thiserror::Error; |
| 4 | + |
| 5 | +/// Represents a broken invariant of [`PartialEq`]. |
| 6 | +#[derive(Error, Debug, Clone)] |
| 7 | +#[non_exhaustive] |
| 8 | +pub enum PartialEqError { |
| 9 | + /// [`PartialEq::ne`] *MUST* always return the negation of [`PartialEq::eq`]. |
| 10 | + #[error("PartialEq::ne MUST always return the negation of PartialEq::eq")] |
| 11 | + BadNe, |
| 12 | + /// If `A: PartialEq<B>` and `B: PartialEq<A>`, then `a == b` *MUST* imply `b == a`. |
| 13 | + #[error("a == b MUST imply b == a")] |
| 14 | + BrokeSymmetry, |
| 15 | + /// If `A: PartialEq<B>` and `B: PartialEq<C>` and `A: PartialEq<C>`, then |
| 16 | + /// `a == b && b == c` *MUST* imply `a == c`. |
| 17 | + #[error("a == b && b == c MUST imply a == c")] |
| 18 | + BrokeTransitivity, |
| 19 | +} |
| 20 | + |
| 21 | +/// Represents a broken invariant of [`Eq`]. |
| 22 | +/// |
| 23 | +/// Note that [`Eq`] also mandates all invariants of [`PartialEq`]. |
| 24 | +#[derive(Error, Debug, Clone)] |
| 25 | +#[non_exhaustive] |
| 26 | +pub enum EqError { |
| 27 | + /// All values must be equal to themselves. |
| 28 | + #[error("a == a MUST be true")] |
| 29 | + BrokeReflexivity, |
| 30 | +} |
| 31 | + |
| 32 | +/// Represents a broken invariant of [`PartialOrd`]. |
| 33 | +/// |
| 34 | +/// Note that [`PartialOrd`] also mandates all invariants of [`PartialEq`]. |
| 35 | +#[derive(Error, Debug, Clone)] |
| 36 | +#[non_exhaustive] |
| 37 | +pub enum PartialOrdError { |
| 38 | + /// [`PartialOrd::partial_cmp`] *MUST* return `Some(Ordering::Equal)` if |
| 39 | + /// and only if [`PartialEq::eq`] returns [`true`]. |
| 40 | + #[error("PartialOrd::partial_cmp MUST return Some(Ordering::Equal) if and only if PartialEq::eq returns true")] |
| 41 | + BadPartialCmp, |
| 42 | + /// [`PartialOrd::lt`] *MUST* return [`true`] |
| 43 | + /// if and only if [`PartialOrd::partial_cmp`] returns `Some(Ordering::Less)`. |
| 44 | + #[error("PartialOrd::lt MUST return true if and only if PartialOrd::partial_cmp returns Some(Ordering::Less)")] |
| 45 | + BadLt, |
| 46 | + /// [`PartialOrd::le`] *MUST* return [`true`] if and only if |
| 47 | + /// [`PartialOrd::partial_cmp`] returns `Some(Ordering::Less)` or |
| 48 | + /// [`Some(Ordering::Equal)`]. |
| 49 | + #[error("PartialOrd::le MUST return true if and only if PartialOrd::partial_cmp returns Some(Ordering::Less) or Some(Ordering::Equal)")] |
| 50 | + BadLe, |
| 51 | + /// [`PartialOrd::gt`] *MUST* return [`true`] if and only if |
| 52 | + /// [`PartialOrd::partial_cmp`] returns `Some(Ordering::Greater)`. |
| 53 | + #[error("PartialOrd::gt MUST return true if and only if PartialOrd::partial_cmp returns Some(Ordering::Greater)")] |
| 54 | + BadGt, |
| 55 | + /// [`PartialOrd::ge`] *MUST* return [`true`] if and only if |
| 56 | + /// [`PartialOrd::partial_cmp`] returns `Some(Ordering::Greater)` or |
| 57 | + /// `Some(Ordering::Equal)`. |
| 58 | + #[error("PartialOrd::ge MUST return true if and only if PartialOrd::partial_cmp returns Some(Ordering::Greater) or Some(Ordering::Equal)")] |
| 59 | + BadGe, |
| 60 | + /// If `a > b`, then `b < a` *MUST* be true. |
| 61 | + #[error("If a > b, then b < a MUST be true")] |
| 62 | + BrokeDuality, |
| 63 | + /// If `a > b` and `b > c`, then `a > c` *MUST* be true. The same must hold true for `<`. |
| 64 | + #[error("If a > b and b > c, then a > c MUST be true. The same must hold true for <")] |
| 65 | + BrokeTransitivity, |
| 66 | +} |
| 67 | + |
| 68 | +/// Represents a broken invariant of [`Ord`]. |
| 69 | +/// |
| 70 | +/// Note that [`Ord`] also mandates all invariants of [`PartialOrd`] and [`Eq`]. |
| 71 | +#[derive(Error, Debug, Clone)] |
| 72 | +#[non_exhaustive] |
| 73 | +pub enum OrdError { |
| 74 | + /// [`Ord::cmp`] *MUST* always return `Some(PartialOrd::partial_cmp())`. |
| 75 | + #[error("`cmp` and `partial_cmp` are not consistent")] |
| 76 | + BadCmp, |
| 77 | + /// [`Ord::cmp`] and [`Ord::max`] are not consistent. |
| 78 | + #[error("`cmp` and `max` are not consistent")] |
| 79 | + BadMax, |
| 80 | + /// [`Ord::cmp`] and [`Ord::min`] are not consistent. |
| 81 | + #[error("`cmp` and `min` are not consistent")] |
| 82 | + BadMin, |
| 83 | + /// [`Ord::cmp`] and [`Ord::clamp`] are not consistent. |
| 84 | + #[error("`cmp` and `clamp` are not consistent")] |
| 85 | + BadClamp, |
| 86 | +} |
| 87 | + |
| 88 | +/// Represents a broken invariant of [`Hash`]. |
| 89 | +#[derive(Error, Debug, Clone)] |
| 90 | +#[non_exhaustive] |
| 91 | +pub enum HashError { |
| 92 | + /// Equal values *MUST* have equal hash values. |
| 93 | + #[error("Equal values MUST have equal hash values")] |
| 94 | + EqualButDifferentHashes, |
| 95 | + /// When two values are different (as defined by [`PartialEq::ne`]), neither |
| 96 | + /// of the two hash outputs can be a prefix of the other. See |
| 97 | + /// <https://doc.rust-lang.org/std/hash/trait.Hash.html#prefix-collisions> |
| 98 | + /// for more information. |
| 99 | + #[error("When two values are different, one of the two hash outputs CAN NOT be a prefix of the other")] |
| 100 | + PrefixCollision, |
| 101 | +} |
| 102 | + |
| 103 | +/// Represents a broken invariant of [`Iterator`]. |
| 104 | +#[derive(Error, Debug, Clone)] |
| 105 | +#[non_exhaustive] |
| 106 | +pub enum IteratorError { |
| 107 | + /// [`Iterator::size_hint`] *MUST* always provide correct lower and upper |
| 108 | + /// bounds. |
| 109 | + #[error("Iterator::size_hint MUST always provide correct lower and upper bounds")] |
| 110 | + BadSizeHint, |
| 111 | + /// [`Iterator::count`] *MUST* be consistent with the actual number of |
| 112 | + /// elements returned by [`Iterator::next`]. |
| 113 | + #[error( |
| 114 | + "Iterator::count MUST be consistent with the actual number of elements returned by .next()" |
| 115 | + )] |
| 116 | + BadCount, |
| 117 | + /// [`Iterator::last`] *MUST* be equal to the last element of the |
| 118 | + /// [`Vec`] resulting from [`Iterator::collect`]. |
| 119 | + #[error(".last() MUST be equal to the last element of the Vec<_> resulting from .collect()")] |
| 120 | + BadLast, |
| 121 | + /// [`DoubleEndedIterator::next_back`] *MUST* return the same values as |
| 122 | + /// [`Iterator::next`], just in reverse order, and it MUST NOT return |
| 123 | + /// different values. |
| 124 | + #[error("DoubleEndedIterator::next_back() MUST return the same values as .next(), but in reverse order")] |
| 125 | + BadNextBack, |
| 126 | + /// [`FusedIterator`](core::iter::FusedIterator) *MUST* return [`None`] |
| 127 | + /// indefinitely after exhaustion. |
| 128 | + #[error("FusedIterator MUST return None indefinitely after exhaustion")] |
| 129 | + FusedIteratorReturnedSomeAfterExhaustion, |
| 130 | +} |
| 131 | + |
| 132 | +/// The crate error type. |
| 133 | +#[derive(Error, Debug, Clone)] |
| 134 | +#[non_exhaustive] |
| 135 | +pub enum Error { |
| 136 | + #[error(transparent)] |
| 137 | + PartialEq(#[from] PartialEqError), |
| 138 | + #[error(transparent)] |
| 139 | + Eq(#[from] EqError), |
| 140 | + #[error(transparent)] |
| 141 | + PartiaOrd(#[from] PartialOrdError), |
| 142 | + #[error(transparent)] |
| 143 | + Ord(#[from] OrdError), |
| 144 | + #[error(transparent)] |
| 145 | + Hash(#[from] HashError), |
| 146 | + #[error(transparent)] |
| 147 | + Iterator(#[from] IteratorError), |
| 148 | +} |
0 commit comments