1 //! Error that occurred at some stage of parsing
2 
3 use core::convert::TryFrom;
4 use core::fmt;
5 
6 use crate::error::{self, ParseFromDescription, TryFromParsed};
7 
8 /// An error that occurred at some stage of parsing.
9 #[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
10 #[allow(variant_size_differences)]
11 #[non_exhaustive]
12 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
13 pub enum Parse {
14     #[allow(clippy::missing_docs_in_private_items)]
15     TryFromParsed(TryFromParsed),
16     #[allow(clippy::missing_docs_in_private_items)]
17     ParseFromDescription(ParseFromDescription),
18     /// The input should have ended, but there were characters remaining.
19     #[non_exhaustive]
20     UnexpectedTrailingCharacters,
21 }
22 
23 impl fmt::Display for Parse {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result24     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25         match self {
26             Self::TryFromParsed(err) => err.fmt(f),
27             Self::ParseFromDescription(err) => err.fmt(f),
28             Self::UnexpectedTrailingCharacters => f.write_str("unexpected trailing characters"),
29         }
30     }
31 }
32 
33 #[cfg(feature = "std")]
34 impl std::error::Error for Parse {
source(&self) -> Option<&(dyn std::error::Error + 'static)>35     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
36         match self {
37             Self::TryFromParsed(err) => Some(err),
38             Self::ParseFromDescription(err) => Some(err),
39             Self::UnexpectedTrailingCharacters => None,
40         }
41     }
42 }
43 
44 #[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
45 impl From<TryFromParsed> for Parse {
from(err: TryFromParsed) -> Self46     fn from(err: TryFromParsed) -> Self {
47         Self::TryFromParsed(err)
48     }
49 }
50 
51 #[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
52 impl TryFrom<Parse> for TryFromParsed {
53     type Error = error::DifferentVariant;
54 
try_from(err: Parse) -> Result<Self, Self::Error>55     fn try_from(err: Parse) -> Result<Self, Self::Error> {
56         match err {
57             Parse::TryFromParsed(err) => Ok(err),
58             _ => Err(error::DifferentVariant),
59         }
60     }
61 }
62 
63 #[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
64 impl From<ParseFromDescription> for Parse {
from(err: ParseFromDescription) -> Self65     fn from(err: ParseFromDescription) -> Self {
66         Self::ParseFromDescription(err)
67     }
68 }
69 
70 #[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
71 impl TryFrom<Parse> for ParseFromDescription {
72     type Error = error::DifferentVariant;
73 
try_from(err: Parse) -> Result<Self, Self::Error>74     fn try_from(err: Parse) -> Result<Self, Self::Error> {
75         match err {
76             Parse::ParseFromDescription(err) => Ok(err),
77             _ => Err(error::DifferentVariant),
78         }
79     }
80 }
81 
82 #[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
83 impl From<Parse> for crate::Error {
from(err: Parse) -> Self84     fn from(err: Parse) -> Self {
85         match err {
86             Parse::TryFromParsed(err) => Self::TryFromParsed(err),
87             Parse::ParseFromDescription(err) => Self::ParseFromDescription(err),
88             Parse::UnexpectedTrailingCharacters => Self::UnexpectedTrailingCharacters,
89         }
90     }
91 }
92 
93 #[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
94 impl TryFrom<crate::Error> for Parse {
95     type Error = error::DifferentVariant;
96 
try_from(err: crate::Error) -> Result<Self, Self::Error>97     fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
98         match err {
99             crate::Error::ParseFromDescription(err) => Ok(Self::ParseFromDescription(err)),
100             crate::Error::UnexpectedTrailingCharacters => Ok(Self::UnexpectedTrailingCharacters),
101             crate::Error::TryFromParsed(err) => Ok(Self::TryFromParsed(err)),
102             _ => Err(error::DifferentVariant),
103         }
104     }
105 }
106 
107 #[cfg(feature = "serde-human-readable")]
108 impl Parse {
109     /// Obtain an error type for the deserializer.
to_invalid_serde_value<'a, D: serde::Deserializer<'a>>(self) -> D::Error110     pub(crate) fn to_invalid_serde_value<'a, D: serde::Deserializer<'a>>(self) -> D::Error {
111         #[cfg(not(feature = "std"))]
112         use alloc::format;
113 
114         use serde::de::Error;
115 
116         match self {
117             Self::TryFromParsed(TryFromParsed::InsufficientInformation) => unreachable!(
118                 "The deserializing format contains all information needed to construct a `Time`."
119             ),
120             Self::TryFromParsed(TryFromParsed::ComponentRange(err)) => {
121                 err.to_invalid_serde_value::<D>()
122             }
123             Self::ParseFromDescription(ParseFromDescription::InvalidLiteral) => {
124                 D::Error::invalid_value(serde::de::Unexpected::Other("literal"), &"valid format")
125             }
126             Self::ParseFromDescription(ParseFromDescription::InvalidComponent(component)) => {
127                 D::Error::invalid_value(
128                     serde::de::Unexpected::Other(component),
129                     &&*format!("valid {}", component),
130                 )
131             }
132             Self::UnexpectedTrailingCharacters => D::Error::invalid_value(
133                 serde::de::Unexpected::Other("literal"),
134                 &"no extraneous characters",
135             ),
136         }
137     }
138 }
139