conv/
errors.rs

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