devela/code/result/
mismatch.rs

1// devela::code::result::mismatch
2//
3//! Define the [`Mismatch`] type.
4//
5
6use crate::{ConstDefault, Interval};
7
8#[doc = crate::TAG_RESULT!()]
9/// Represents a mismatch between an expected `need` and an encountered `have`.
10///
11/// With optional contextual information in the `info` field.
12///
13/// This struct conveys optional information about the anticipated `need` and
14/// the observed `have`, allowing for either, both, or none to be specified.
15///
16/// It can be particularly useful for error handling and reporting.
17pub struct Mismatch<N, H> {
18    /// Information about something that was needed, expected or anticipated.
19    pub need: N,
20
21    /// Information about something that was obtained, observed, or encountered.
22    pub have: H,
23
24    /// Contextual static information about the mismatch.
25    pub info: &'static str,
26}
27
28impl<N, H> Mismatch<N, H> {
29    /// Creates a new `Mismatch` with the specified `need` and `have`.
30    #[must_use]
31    pub const fn new(need: N, have: H) -> Self {
32        Self { need, have, info: "" }
33    }
34
35    /// Creates a new `Mismatch` with the specified `need`, `have`, and `info`.
36    #[must_use]
37    pub const fn with_info(need: N, have: H, info: &'static str) -> Self {
38        Self { need, have, info }
39    }
40}
41
42impl<N, H> Mismatch<Interval<N>, H> {
43    /// Creates a mismatch where `need` is an [`Interval::point`],
44    /// and `have` does not match.
45    #[must_use] #[rustfmt::skip]
46    pub fn in_point_interval(need_point: N, have: H, info: &'static str) -> Self where N: Clone {
47        Self { need: Interval::point(need_point), have, info }
48    }
49
50    /// Creates a mismatch where `need` is an [`Interval::empty`],
51    /// but `have` was provided.
52    #[must_use] #[rustfmt::skip]
53    pub fn in_empty_interval(have: H, info: &'static str) -> Self where N: Default {
54        Self { need: Interval::empty(), have, info }
55    }
56    /// Creates a mismatch where `need` is an [`Interval::empty_const`],
57    /// but `have` was provided.
58    #[must_use] #[rustfmt::skip]
59    pub const fn in_empty_const_interval(have: H, info: &'static str) -> Self
60    where N: ConstDefault {
61        Self { need: Interval::empty_const(), have, info }
62    }
63    /// Creates a mismatch where `need` is an [`Interval::empty_with`],
64    /// but `have` was provided.
65    #[must_use] #[rustfmt::skip]
66    pub fn in_empty_interval_with(value: N, have: H, info: &'static str) -> Self where N: Clone {
67        Self { need: Interval::empty_with(value), have, info }
68    }
69
70    /// Creates a mismatch where `need` is an [`Interval::closed`],
71    /// and `have` is outside it.
72    #[must_use]
73    pub const fn in_closed_interval(lower: N, upper: N, have: H, info: &'static str) -> Self {
74        Self { need: Interval::closed(lower, upper), have, info }
75    }
76
77    /// Creates a mismatch where `need` is an [`Interval::closed_open`],
78    /// and `have` is outside it.
79    #[must_use]
80    pub const fn in_closed_open_interval(lower: N, upper: N, have: H, info: &'static str) -> Self {
81        Self {
82            need: Interval::closed_open(lower, upper),
83            have,
84            info,
85        }
86    }
87
88    /// Creates a mismatch where `need` is an [`Interval::open`],
89    /// and `have` is outside it.
90    #[must_use]
91    pub const fn in_open_interval(lower: N, upper: N, have: H, info: &'static str) -> Self {
92        Self { need: Interval::open(lower, upper), have, info }
93    }
94}
95
96mod core_impls {
97    use crate::{
98        ConstDefault, Debug, Display, FmtResult, Formatter, Hash, Hasher, Mismatch, Ordering,
99    };
100
101    impl<N: Clone, H: Clone> Clone for Mismatch<N, H> {
102        fn clone(&self) -> Self {
103            Self {
104                need: self.need.clone(),
105                have: self.have.clone(),
106                info: self.info,
107            }
108        }
109    }
110    impl<N: Copy, H: Copy> Copy for Mismatch<N, H> {}
111
112    impl<N: Default, H: Default> Default for Mismatch<N, H> {
113        /// Returns a default `Mismatch`.
114        fn default() -> Self {
115            Self {
116                need: Default::default(),
117                have: Default::default(),
118                info: "",
119            }
120        }
121    }
122    impl<N: ConstDefault, H: ConstDefault> ConstDefault for Mismatch<N, H> {
123        /// Returns a *const* default `Mismatch`.
124        const DEFAULT: Self = Self { need: N::DEFAULT, have: H::DEFAULT, info: "" };
125    }
126
127    impl<N: Debug, H: Debug> Debug for Mismatch<N, H> {
128        fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
129            let mut debug = f.debug_struct("Mismatch");
130            debug.field("need", &self.need);
131            debug.field("have", &self.have);
132            debug.field("info", &self.info);
133            debug.finish()
134        }
135    }
136
137    impl<N: Display, H: Display> Display for Mismatch<N, H> {
138        fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
139            write!(
140                f,
141                "Mismatch {{ need: {}, have: {}, info: {} }}",
142                self.need, self.have, self.info
143            )
144        }
145    }
146
147    impl<N: PartialEq, H: PartialEq> PartialEq for Mismatch<N, H> {
148        fn eq(&self, other: &Self) -> bool {
149            self.need == other.need && self.have == other.have && self.info == other.info
150        }
151    }
152    impl<N: Eq, H: Eq> Eq for Mismatch<N, H> {}
153
154    impl<N: PartialOrd, H: PartialOrd> PartialOrd for Mismatch<N, H> {
155        /// Compare need first. If they are equal, then compare have.
156        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
157            match self.need.partial_cmp(&other.need) {
158                Some(Ordering::Equal) => match self.have.partial_cmp(&other.have) {
159                    Some(Ordering::Equal) => self.info.partial_cmp(other.info),
160                    other => other,
161                },
162                other => other,
163            }
164        }
165    }
166    impl<N: Ord, H: Ord> Ord for Mismatch<N, H> {
167        /// Compare need first. If they are equal, then compare have.
168        fn cmp(&self, other: &Self) -> Ordering {
169            match self.need.cmp(&other.need) {
170                Ordering::Equal => match self.have.cmp(&other.have) {
171                    Ordering::Equal => self.info.cmp(other.info),
172                    order => order,
173                },
174                order => order,
175            }
176        }
177    }
178
179    impl<N: Hash, H: Hash> Hash for Mismatch<N, H> {
180        fn hash<HR: Hasher>(&self, state: &mut HR) {
181            self.need.hash(state);
182            self.have.hash(state);
183        }
184    }
185}