conv2/
errors.rs

1//! This module defines the various error types that can be produced by a
2//! failed conversion.
3//!
4//! In addition, it also defines some extension traits to make working with
5//! failable conversions more ergonomic (see the `Unwrap*` traits).
6
7use crate::misc::{InvalidSentinel, Saturated, SignedInfinity};
8use core::fmt::{self, Debug, Display};
9
10/// A general error enumeration that subsumes all other conversion errors.
11///
12/// This exists primarily as a "catch-all" for reliably unifying various
13/// different kinds of conversion errors.
14#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, thiserror::Error)]
15pub enum GeneralError<T> {
16    /// Input was too negative for the target type.
17    #[error("conversion resulted in negative overflow")]
18    NegOverflow(T),
19
20    /// Input was too positive for the target type.
21    #[error("conversion resulted in positive overflow")]
22    PosOverflow(T),
23
24    /// Input was not representable in the target type.
25    #[error("could not convert unrepresentable value")]
26    Unrepresentable(T),
27}
28
29impl<T> GeneralError<T> {
30    /// Returns the value stored in this error.
31    pub fn into_inner(self) -> T {
32        match self {
33            GeneralError::NegOverflow(v)
34            | GeneralError::PosOverflow(v)
35            | GeneralError::Unrepresentable(v) => v,
36        }
37    }
38}
39
40impl<T> From<NoError> for GeneralError<T> {
41    fn from(_: NoError) -> Self {
42        unreachable!();
43    }
44}
45
46impl<T> From<Unrepresentable<T>> for GeneralError<T> {
47    fn from(e: Unrepresentable<T>) -> Self {
48        GeneralError::Unrepresentable(e.0)
49    }
50}
51
52impl<T> From<NegOverflow<T>> for GeneralError<T> {
53    fn from(e: NegOverflow<T>) -> Self {
54        GeneralError::NegOverflow(e.0)
55    }
56}
57
58impl<T> From<PosOverflow<T>> for GeneralError<T> {
59    fn from(e: PosOverflow<T>) -> Self {
60        GeneralError::PosOverflow(e.0)
61    }
62}
63
64impl<T> From<RangeError<T>> for GeneralError<T> {
65    fn from(e: RangeError<T>) -> Self {
66        match e {
67            RangeError::NegOverflow(v) => GeneralError::NegOverflow(v),
68            RangeError::PosOverflow(v) => GeneralError::PosOverflow(v),
69        }
70    }
71}
72
73impl<T> From<FloatError<T>> for GeneralError<T> {
74    fn from(e: FloatError<T>) -> GeneralError<T> {
75        use self::FloatError as F;
76        use self::GeneralError as G;
77        match e {
78            F::NegOverflow(v) => G::NegOverflow(v),
79            F::PosOverflow(v) => G::PosOverflow(v),
80            F::NotANumber(v) => G::Unrepresentable(v),
81        }
82    }
83}
84
85/// A general error enumeration that subsumes all other conversion errors,
86/// but discards all input payloads the errors may be carrying.
87///
88/// This exists primarily as a "catch-all" for reliably unifying various
89/// different kinds of conversion errors, and between different input types.
90#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, thiserror::Error)]
91pub enum GeneralErrorKind {
92    /// Input was too negative for the target type.
93    #[error("conversion resulted in negative overflow")]
94    NegOverflow,
95
96    /// Input was too positive for the target type.
97    #[error("conversion resulted in positive overflow")]
98    PosOverflow,
99
100    /// Input was not representable in the target type.
101    #[error("could not convert unrepresentable value")]
102    Unrepresentable,
103}
104
105impl From<NoError> for GeneralErrorKind {
106    fn from(_: NoError) -> Self {
107        unreachable!();
108    }
109}
110
111impl<T> From<Unrepresentable<T>> for GeneralErrorKind {
112    fn from(_: Unrepresentable<T>) -> Self {
113        GeneralErrorKind::Unrepresentable
114    }
115}
116
117impl<T> From<NegOverflow<T>> for GeneralErrorKind {
118    fn from(_: NegOverflow<T>) -> Self {
119        GeneralErrorKind::NegOverflow
120    }
121}
122
123impl<T> From<PosOverflow<T>> for GeneralErrorKind {
124    fn from(_: PosOverflow<T>) -> Self {
125        GeneralErrorKind::PosOverflow
126    }
127}
128
129impl From<RangeErrorKind> for GeneralErrorKind {
130    fn from(e: RangeErrorKind) -> Self {
131        match e {
132            RangeErrorKind::NegOverflow => GeneralErrorKind::NegOverflow,
133            RangeErrorKind::PosOverflow => GeneralErrorKind::PosOverflow,
134        }
135    }
136}
137impl<T> From<RangeError<T>> for GeneralErrorKind {
138    fn from(e: RangeError<T>) -> Self {
139        match e {
140            RangeError::NegOverflow(..) => GeneralErrorKind::NegOverflow,
141            RangeError::PosOverflow(..) => GeneralErrorKind::PosOverflow,
142        }
143    }
144}
145impl<T> From<GeneralError<T>> for GeneralErrorKind {
146    fn from(e: GeneralError<T>) -> Self {
147        match e {
148            GeneralError::NegOverflow(..) => GeneralErrorKind::NegOverflow,
149            GeneralError::PosOverflow(..) => GeneralErrorKind::PosOverflow,
150            GeneralError::Unrepresentable(..) => GeneralErrorKind::Unrepresentable,
151        }
152    }
153}
154
155impl<T> From<FloatError<T>> for GeneralErrorKind {
156    fn from(e: FloatError<T>) -> GeneralErrorKind {
157        use self::FloatError as F;
158        use self::GeneralErrorKind as G;
159        match e {
160            F::NegOverflow(..) => G::NegOverflow,
161            F::PosOverflow(..) => G::PosOverflow,
162            F::NotANumber(..) => G::Unrepresentable,
163        }
164    }
165}
166
167/// Indicates that it is not possible for the conversion to fail.
168///
169/// You can use the [`UnwrapOk::unwrap_ok`] method to discard the (statically impossible)
170/// `Err` case from a `Result<_, NoError>`, without using `Result::unwrap` (which is
171/// typically viewed as a "code smell").
172#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
173pub enum NoError {}
174
175impl Display for NoError {
176    fn fmt(&self, _: &mut fmt::Formatter) -> Result<(), fmt::Error> {
177        unreachable!()
178    }
179}
180
181impl std::error::Error for NoError {}
182
183/// Indicates that the conversion failed because the value was not representable.
184#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, thiserror::Error)]
185#[error("could not convert unrepresentable value")]
186pub struct Unrepresentable<T>(pub T);
187
188impl<T> From<NoError> for Unrepresentable<T> {
189    fn from(_: NoError) -> Self {
190        unreachable!();
191    }
192}
193
194/// Indicates that the conversion failed due to a negative overflow.
195#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, thiserror::Error)]
196#[error("conversion resulted in negative overflow")]
197pub struct NegOverflow<T>(pub T);
198
199impl<T> From<NoError> for NegOverflow<T> {
200    fn from(_: NoError) -> Self {
201        unreachable!();
202    }
203}
204
205/// Indicates that the conversion failed due to a positive overflow.
206#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, thiserror::Error)]
207#[error("conversion resulted in positive overflow")]
208pub struct PosOverflow<T>(pub T);
209
210impl<T> From<NoError> for PosOverflow<T> {
211    fn from(_: NoError) -> Self {
212        unreachable!();
213    }
214}
215
216/// Indicates that a conversion from a floating point type failed.
217#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, thiserror::Error)]
218pub enum FloatError<T> {
219    /// Input was too negative for the target type.
220    #[error("conversion resulted in negative overflow")]
221    NegOverflow(T),
222
223    /// Input was too positive for the target type.
224    #[error("conversion resulted in positive overflow")]
225    PosOverflow(T),
226
227    /// Input was not-a-number, which the target type could not represent.
228    #[error("conversion target does not support not-a-number")]
229    NotANumber(T),
230}
231
232impl<T> FloatError<T> {
233    /// Returns the value stored in this error.
234    pub fn into_inner(self) -> T {
235        match self {
236            FloatError::NegOverflow(v) | FloatError::PosOverflow(v) | FloatError::NotANumber(v) => {
237                v
238            }
239        }
240    }
241}
242
243impl<T> From<NoError> for FloatError<T> {
244    fn from(_: NoError) -> Self {
245        unreachable!();
246    }
247}
248
249impl<T> From<NegOverflow<T>> for FloatError<T> {
250    fn from(e: NegOverflow<T>) -> Self {
251        FloatError::NegOverflow(e.0)
252    }
253}
254
255impl<T> From<PosOverflow<T>> for FloatError<T> {
256    fn from(e: PosOverflow<T>) -> Self {
257        FloatError::PosOverflow(e.0)
258    }
259}
260
261impl<T> From<RangeError<T>> for FloatError<T> {
262    fn from(e: RangeError<T>) -> Self {
263        match e {
264            RangeError::NegOverflow(v) => FloatError::NegOverflow(v),
265            RangeError::PosOverflow(v) => FloatError::PosOverflow(v),
266        }
267    }
268}
269
270/// Indicates that a conversion failed due to a range error.
271#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, thiserror::Error)]
272pub enum RangeError<T> {
273    /// Input was too negative for the target type.
274    #[error("conversion resulted in negative overflow")]
275    NegOverflow(T),
276
277    /// Input was too positive the target type.
278    #[error("conversion resulted in positive overflow")]
279    PosOverflow(T),
280}
281
282impl<T> From<NoError> for RangeError<T> {
283    fn from(_: NoError) -> Self {
284        unreachable!();
285    }
286}
287
288impl<T> From<NegOverflow<T>> for RangeError<T> {
289    fn from(e: NegOverflow<T>) -> Self {
290        RangeError::NegOverflow(e.0)
291    }
292}
293
294impl<T> From<PosOverflow<T>> for RangeError<T> {
295    fn from(e: PosOverflow<T>) -> Self {
296        RangeError::PosOverflow(e.0)
297    }
298}
299
300/// Indicates that a conversion failed due to a range error.
301///
302/// This is a variant of `RangeError` that does not retain the input value
303/// which caused the error. It exists to help unify some utility methods
304/// and should not generally be used directly, unless you are targeting the
305/// `Unwrap*` traits.
306#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, thiserror::Error)]
307pub enum RangeErrorKind {
308    /// Input was too negative for the target type.
309    #[error("conversion resulted in negative overflow")]
310    NegOverflow,
311
312    /// Input was too positive the target type.
313    #[error("conversion resulted in positive overflow")]
314    PosOverflow,
315}
316
317impl From<NoError> for RangeErrorKind {
318    fn from(_: NoError) -> Self {
319        unreachable!();
320    }
321}
322
323impl<T> From<NegOverflow<T>> for RangeErrorKind {
324    fn from(_: NegOverflow<T>) -> Self {
325        RangeErrorKind::NegOverflow
326    }
327}
328
329impl<T> From<PosOverflow<T>> for RangeErrorKind {
330    fn from(_: PosOverflow<T>) -> Self {
331        RangeErrorKind::PosOverflow
332    }
333}
334
335impl<T> From<RangeError<T>> for RangeErrorKind {
336    fn from(e: RangeError<T>) -> Self {
337        match e {
338            RangeError::NegOverflow(..) => RangeErrorKind::NegOverflow,
339            RangeError::PosOverflow(..) => RangeErrorKind::PosOverflow,
340        }
341    }
342}
343
344/// Saturates a `Result`.
345pub trait Saturate {
346    /// The result of saturating.
347    type Output;
348
349    /// Replaces an overflow error with a saturated value.
350    ///
351    /// Unlike `unwrap_or_saturate`, this method can be used in cases where the
352    /// `Result` error type can encode failures *other* than overflow and
353    /// underflow. For example, you cannot saturate a float-to-integer conversion using `unwrap_or_saturate` as the error might be `NotANumber`, which doesn't have a meaningful saturation "direction".
354    ///
355    /// The output of this method will be a `Result` where the error type *does not* contain overflow conditions. What conditions remain must still be dealt with in some fashion.
356    fn saturate(self) -> Self::Output;
357}
358
359impl<T, U> Saturate for Result<T, FloatError<U>>
360where
361    T: Saturated,
362{
363    type Output = Result<T, Unrepresentable<U>>;
364
365    fn saturate(self) -> Self::Output {
366        use self::FloatError::*;
367        match self {
368            Ok(v) => Ok(v),
369            Err(NegOverflow(_)) => Ok(T::saturated_min()),
370            Err(PosOverflow(_)) => Ok(T::saturated_max()),
371            Err(NotANumber(v)) => Err(Unrepresentable(v)),
372        }
373    }
374}
375
376impl<T, U> Saturate for Result<T, RangeError<U>>
377where
378    T: Saturated,
379{
380    type Output = Result<T, NoError>;
381
382    fn saturate(self) -> Self::Output {
383        use self::RangeError::*;
384        match self {
385            Ok(v) => Ok(v),
386            Err(NegOverflow(_)) => Ok(T::saturated_min()),
387            Err(PosOverflow(_)) => Ok(T::saturated_max()),
388        }
389    }
390}
391
392impl<T> Saturate for Result<T, RangeErrorKind>
393where
394    T: Saturated,
395{
396    type Output = Result<T, NoError>;
397
398    fn saturate(self) -> Self::Output {
399        use self::RangeErrorKind::*;
400        match self {
401            Ok(v) => Ok(v),
402            Err(NegOverflow) => Ok(T::saturated_min()),
403            Err(PosOverflow) => Ok(T::saturated_max()),
404        }
405    }
406}
407
408/// Safely unwrap a `Result` that cannot contain an error.
409pub trait UnwrapOk<T> {
410    /// Unwraps a `Result` without possibility of failing.
411    ///
412    /// Technically, this is not necessary; it's provided simply to make user
413    /// code a little clearer.
414    fn unwrap_ok(self) -> T;
415}
416
417impl<T> UnwrapOk<T> for Result<T, NoError> {
418    fn unwrap_ok(self) -> T {
419        match self {
420            Ok(v) => v,
421            Err(no_error) => match no_error {},
422        }
423    }
424}
425
426/// Unwrap a conversion by saturating to infinity.
427pub trait UnwrapOrInf {
428    /// The result of unwrapping.
429    type Output;
430
431    /// Either unwraps the successfully converted value, or saturates to
432    /// infinity in the "direction" of overflow.
433    fn unwrap_or_inf(self) -> Self::Output;
434}
435
436/// Unwrap a conversion by replacing a failure with an invalid sentinel value.
437pub trait UnwrapOrInvalid {
438    /// The result of unwrapping.
439    type Output;
440
441    /// Either unwraps the successfully converted value, or returns the output
442    /// type's invalid sentinel value.
443    fn unwrap_or_invalid(self) -> Self::Output;
444}
445
446/// Unwrap a conversion by saturating.
447pub trait UnwrapOrSaturate {
448    /// The result of unwrapping.
449    type Output;
450
451    /// Either unwraps the successfully converted value, or saturates in the
452    /// "direction" of overflow.
453    fn unwrap_or_saturate(self) -> Self::Output;
454}
455
456impl<T, E> UnwrapOrInf for Result<T, E>
457where
458    T: SignedInfinity,
459    E: Into<RangeErrorKind>,
460{
461    type Output = T;
462    fn unwrap_or_inf(self) -> T {
463        use self::RangeErrorKind::*;
464        match self.map_err(Into::into) {
465            Ok(v) => v,
466            Err(NegOverflow) => T::neg_infinity(),
467            Err(PosOverflow) => T::pos_infinity(),
468        }
469    }
470}
471
472impl<T, E> UnwrapOrInvalid for Result<T, E>
473where
474    T: InvalidSentinel,
475{
476    type Output = T;
477    fn unwrap_or_invalid(self) -> T {
478        match self {
479            Ok(v) => v,
480            Err(..) => T::invalid_sentinel(),
481        }
482    }
483}
484
485impl<T, E> UnwrapOrSaturate for Result<T, E>
486where
487    T: Saturated,
488    E: Into<RangeErrorKind>,
489{
490    type Output = T;
491    fn unwrap_or_saturate(self) -> T {
492        use self::RangeErrorKind::*;
493        match self.map_err(Into::into) {
494            Ok(v) => v,
495            Err(NegOverflow) => T::saturated_min(),
496            Err(PosOverflow) => T::saturated_max(),
497        }
498    }
499}