1use crate::Location;
2use std::fmt::{self, Display, Formatter};
3
4#[derive(Debug, Clone, PartialEq)]
12pub enum Error {
13 InvalidUtf8 {
14 location: Box<Location>,
15 },
16 UnsupportedType {
17 location: Box<Location>,
18 found: &'static str,
19 },
20 Parse {
21 location: Option<Box<Location>>,
22 message: String,
23 },
24 #[cfg(feature = "serde")]
31 Deserialize {
32 message: String,
33 location: Option<Box<Location>>,
34 },
35}
36
37impl Error {
38 #[cfg(feature = "serde")]
42 pub(crate) fn or_location(mut self, location: &Location) -> Self {
43 if let Self::Deserialize {
44 location: slot @ None,
45 ..
46 } = &mut self
47 {
48 *slot = Some(Box::new(location.clone()));
49 }
50 self
51 }
52}
53
54fn located_message(location: &Location, message: &str) -> String {
55 format!("{message} at {location}")
56}
57
58impl Display for Error {
59 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
60 match self {
61 Self::InvalidUtf8 { location } => {
62 write!(f, "invalid utf-8 in configuration input from {location}")?;
63 }
64 Self::UnsupportedType { location, found } => {
65 write!(
66 f,
67 "{}",
68 located_message(
69 location,
70 &format!("unsupported configuration input type `{found}`"),
71 )
72 )?;
73 }
74 Self::Parse {
75 location: Some(location),
76 message,
77 } => write!(f, "{}", located_message(location, message))?,
78 Self::Parse { message, .. } => write!(f, "{message}")?,
79 #[cfg(feature = "serde")]
80 Self::Deserialize {
81 message,
82 location: Some(location),
83 } => write!(
84 f,
85 "{}",
86 located_message(
87 location,
88 &format!("failed to deserialize configuration: {message}"),
89 )
90 )?,
91 #[cfg(feature = "serde")]
92 Self::Deserialize { message, .. } => {
93 write!(f, "failed to deserialize configuration: {message}")?
94 }
95 }
96
97 if f.alternate() {
100 let location = match self {
101 Self::InvalidUtf8 { location } | Self::UnsupportedType { location, .. } => {
102 Some(location.as_ref())
103 }
104 Self::Parse {
105 location: Some(location),
106 ..
107 } => Some(location.as_ref()),
108 #[cfg(feature = "serde")]
109 Self::Deserialize {
110 location: Some(location),
111 ..
112 } => Some(location.as_ref()),
113 _ => None,
114 };
115 if let Some(location) = location
116 && !location.snippet.is_empty()
117 {
118 write!(f, "\n{}", location.snippet)?;
119 }
120 }
121
122 Ok(())
123 }
124}
125
126impl std::error::Error for Error {}