ocpi_tariffs/
enumeration.rs1use crate::{json, warning};
2
3#[derive(Clone, Debug)]
8pub(crate) enum Enum<T> {
9 Known(T),
10 Unknown(String),
11}
12
13pub(crate) trait IntoEnum: Sized {
17 fn enum_from_str(s: &str) -> Enum<Self>;
18}
19
20#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
22pub struct Warning {
23 type_name: &'static str,
25
26 kind: WarningKind,
28}
29
30#[cfg(test)]
31impl Warning {
32 pub(crate) fn type_name(&self) -> &'static str {
33 self.type_name
34 }
35
36 pub(crate) fn kind(&self) -> &WarningKind {
37 &self.kind
38 }
39}
40
41impl std::fmt::Display for Warning {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 match &self.kind {
44 WarningKind::ContainsEscapeCodes => write!(
45 f,
46 "The {} value contains escape codes but it does not need them.",
47 self.type_name
48 ),
49 WarningKind::Decode(warning) => std::fmt::Display::fmt(&warning, f),
50 WarningKind::PreferUpperCase => {
51 write!(f, "The `{}` should be uppercase.", self.type_name)
52 }
53 WarningKind::InvalidVariant => {
54 write!(f, "The value is not a valid `{}`.", self.type_name)
55 }
56 WarningKind::InvalidType => {
57 write!(f, "A {} value should be a string.", self.type_name)
58 }
59 }
60 }
61}
62
63impl crate::Warning for Warning {
64 fn id(&self) -> warning::Id {
65 match &self.kind {
66 WarningKind::ContainsEscapeCodes => warning::Id::from_static("contains_escape_codes"),
67 WarningKind::Decode(warning) => warning.id(),
68 WarningKind::PreferUpperCase => warning::Id::from_static("prefer_upper_case"),
69 WarningKind::InvalidVariant => warning::Id::from_static("invalid_variant"),
70
71 WarningKind::InvalidType => warning::Id::from_static("invalid_type"),
72 }
73 }
74}
75
76#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
77pub enum WarningKind {
78 ContainsEscapeCodes,
80
81 Decode(json::decode::Warning),
83
84 PreferUpperCase,
86
87 InvalidVariant,
89
90 InvalidType,
92}
93
94impl WarningKind {
95 pub(crate) fn into_warning(self, type_name: &'static str) -> Warning {
97 Warning {
98 type_name,
99 kind: self,
100 }
101 }
102}
103
104#[macro_export]
108macro_rules! define_enum_from_json {
109 ($kind:ident, display_name: $name:literal, warning_id: $warning:literal) => {
110 impl $crate::json::FromJson<'_> for $kind {
111 type Warning = $crate::enumeration::Warning;
112
113 fn from_json(elem: &$crate::json::Element<'_>) -> $crate::Verdict<Self, Self::Warning> {
114 use $crate::warning::IntoCaveat as _;
115
116 let value = Enum::<$kind>::from_json(elem)?;
117 let (value, warnings) = value.into_parts();
118
119 let value = match value {
120 $crate::Enum::Known(v) => v,
121 $crate::Enum::Unknown(_) => {
122 return warnings.bail(
123 $crate::enumeration::WarningKind::InvalidVariant
124 .into_warning(stringify!($kind)),
125 elem,
126 );
127 }
128 };
129
130 Ok(value.into_caveat(warnings))
131 }
132 }
133
134 impl $crate::json::FromJson<'_> for $crate::Enum<$kind> {
135 type Warning = $crate::enumeration::Warning;
136
137 fn from_json(elem: &$crate::json::Element<'_>) -> $crate::Verdict<Self, Self::Warning> {
138 use $crate::warning::IntoCaveat as _;
139
140 let mut warnings = $crate::warning::Set::new();
141 let value = elem.as_value();
142
143 let Some(s) = value.to_raw_str() else {
144 return warnings.bail(
145 $crate::enumeration::WarningKind::InvalidType
146 .into_warning(stringify!($kind)),
147 elem,
148 );
149 };
150
151 let (s, inner_warnings) = s.has_escapes(elem).into_parts();
155 let inner_warnings =
156 inner_warnings
157 .into_inner()
158 .into_iter()
159 .map(|(elem_id, group)| {
160 (
161 elem_id,
162 group.map(|w| {
163 $crate::enumeration::WarningKind::Decode(w)
164 .into_warning(stringify!($kind))
165 }),
166 )
167 });
168
169 warnings.extend(inner_warnings);
170
171 let s = match s {
172 $crate::json::decode::PendingStr::NoEscapes(s) => s,
173 $crate::json::decode::PendingStr::HasEscapes(_) => {
174 return warnings.bail(
175 $crate::enumeration::WarningKind::ContainsEscapeCodes
176 .into_warning(stringify!($kind)),
177 elem,
178 );
179 }
180 };
181
182 if !s.chars().all(|c| c.is_uppercase() || c == '_') {
183 warnings.insert(
184 $crate::enumeration::WarningKind::PreferUpperCase
185 .into_warning(stringify!($kind)),
186 elem,
187 );
188 }
189
190 let value = $kind::enum_from_str(s);
191
192 Ok(value.into_caveat(warnings))
193 }
194 }
195 };
196}