devela/code/result/
mismatch.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// devela::code::result::mismatch
//
//! Define the [`Mismatch`] type.
//

use crate::{ConstDefault, Interval};

/// Represents a mismatch between an expected `need` and an encountered `have`.
///
/// With optional contextual information in the `info` field.
///
/// This struct conveys optional information about the anticipated `need` and
/// the observed `have`, allowing for either, both, or none to be specified.
///
/// It can be particularly useful for error handling and reporting.
pub struct Mismatch<N, H> {
    /// Information about something that was needed, expected or anticipated.
    pub need: N,

    /// Information about something that was obtained, observed, or encountered.
    pub have: H,

    /// Contextual static information about the mismatch.
    pub info: &'static str,
}

impl<N, H> Mismatch<N, H> {
    /// Creates a new `Mismatch` with the specified `need` and `have`.
    #[must_use]
    pub const fn new(need: N, have: H) -> Self {
        Self { need, have, info: "" }
    }

    /// Creates a new `Mismatch` with the specified `need`, `have`, and `info`.
    #[must_use]
    pub const fn with_info(need: N, have: H, info: &'static str) -> Self {
        Self { need, have, info }
    }
}

impl<N, H> Mismatch<Interval<N>, H> {
    /// Creates a mismatch where `need` is an [`Interval::point`],
    /// and `have` does not match.
    #[must_use] #[rustfmt::skip]
    pub fn in_point_interval(need_point: N, have: H, info: &'static str) -> Self where N: Clone {
        Self { need: Interval::point(need_point), have, info }
    }

    /// Creates a mismatch where `need` is an [`Interval::empty`],
    /// but `have` was provided.
    #[must_use] #[rustfmt::skip]
    pub fn in_empty_interval(have: H, info: &'static str) -> Self where N: Default {
        Self { need: Interval::empty(), have, info }
    }
    /// Creates a mismatch where `need` is an [`Interval::empty_const`],
    /// but `have` was provided.
    #[must_use] #[rustfmt::skip]
    pub const fn in_empty_const_interval(have: H, info: &'static str) -> Self
    where N: ConstDefault {
        Self { need: Interval::empty_const(), have, info }
    }
    /// Creates a mismatch where `need` is an [`Interval::empty_with`],
    /// but `have` was provided.
    #[must_use] #[rustfmt::skip]
    pub fn in_empty_interval_with(value: N, have: H, info: &'static str) -> Self where N: Clone {
        Self { need: Interval::empty_with(value), have, info }
    }

    /// Creates a mismatch where `need` is an [`Interval::closed`],
    /// and `have` is outside it.
    #[must_use]
    pub const fn in_closed_interval(lower: N, upper: N, have: H, info: &'static str) -> Self {
        Self { need: Interval::closed(lower, upper), have, info }
    }

    /// Creates a mismatch where `need` is an [`Interval::closed_open`],
    /// and `have` is outside it.
    #[must_use]
    pub const fn in_closed_open_interval(lower: N, upper: N, have: H, info: &'static str) -> Self {
        Self {
            need: Interval::closed_open(lower, upper),
            have,
            info,
        }
    }

    /// Creates a mismatch where `need` is an [`Interval::open`],
    /// and `have` is outside it.
    #[must_use]
    pub const fn in_open_interval(lower: N, upper: N, have: H, info: &'static str) -> Self {
        Self { need: Interval::open(lower, upper), have, info }
    }
}

mod core_impls {
    use crate::{
        ConstDefault, Debug, Display, FmtResult, Formatter, Hash, Hasher, Mismatch, Ordering,
    };

    impl<N: Clone, H: Clone> Clone for Mismatch<N, H> {
        fn clone(&self) -> Self {
            Self {
                need: self.need.clone(),
                have: self.have.clone(),
                info: self.info,
            }
        }
    }
    impl<N: Copy, H: Copy> Copy for Mismatch<N, H> {}

    impl<N: Default, H: Default> Default for Mismatch<N, H> {
        /// Returns a default `Mismatch`.
        #[must_use]
        fn default() -> Self {
            Self {
                need: Default::default(),
                have: Default::default(),
                info: "",
            }
        }
    }
    impl<N: ConstDefault, H: ConstDefault> ConstDefault for Mismatch<N, H> {
        /// Returns a *const* default `Mismatch`.
        const DEFAULT: Self = Self { need: N::DEFAULT, have: H::DEFAULT, info: "" };
    }

    impl<N: Debug, H: Debug> Debug for Mismatch<N, H> {
        fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
            let mut debug = f.debug_struct("Mismatch");
            debug.field("need", &self.need);
            debug.field("have", &self.have);
            debug.field("info", &self.info);
            debug.finish()
        }
    }

    impl<N: Display, H: Display> Display for Mismatch<N, H> {
        fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
            write!(
                f,
                "Mismatch {{ need: {}, have: {}, info: {} }}",
                self.need, self.have, self.info
            )
        }
    }

    impl<N: PartialEq, H: PartialEq> PartialEq for Mismatch<N, H> {
        fn eq(&self, other: &Self) -> bool {
            self.need == other.need && self.have == other.have && self.info == other.info
        }
    }
    impl<N: Eq, H: Eq> Eq for Mismatch<N, H> {}

    impl<N: PartialOrd, H: PartialOrd> PartialOrd for Mismatch<N, H> {
        /// Compare need first. If they are equal, then compare have.
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
            match self.need.partial_cmp(&other.need) {
                Some(Ordering::Equal) => match self.have.partial_cmp(&other.have) {
                    Some(Ordering::Equal) => self.info.partial_cmp(other.info),
                    other => other,
                },
                other => other,
            }
        }
    }
    impl<N: Ord, H: Ord> Ord for Mismatch<N, H> {
        /// Compare need first. If they are equal, then compare have.
        fn cmp(&self, other: &Self) -> Ordering {
            match self.need.cmp(&other.need) {
                Ordering::Equal => match self.have.cmp(&other.have) {
                    Ordering::Equal => self.info.cmp(other.info),
                    order => order,
                },
                order => order,
            }
        }
    }

    impl<N: Hash, H: Hash> Hash for Mismatch<N, H> {
        fn hash<HR: Hasher>(&self, state: &mut HR) {
            self.need.hash(state);
            self.have.hash(state);
        }
    }
}