1use crate::{
2 utils::{impl_str_basic, impl_try_from},
3 Error, Result,
4};
5use serde::{de, Deserialize, Serialize};
6use static_assertions::assert_impl_all;
7use std::{
8 borrow::{Borrow, Cow},
9 fmt::{self, Debug, Display, Formatter},
10 ops::Deref,
11 sync::Arc,
12};
13use zvariant::{NoneValue, OwnedValue, Str, Type, Value};
14
15#[derive(
44 Clone, Debug, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue,
45)]
46pub struct ErrorName<'name>(Str<'name>);
47
48assert_impl_all!(ErrorName<'_>: Send, Sync, Unpin);
49
50impl_str_basic!(ErrorName<'_>);
51
52impl<'name> ErrorName<'name> {
53 pub fn as_ref(&self) -> ErrorName<'_> {
55 ErrorName(self.0.as_ref())
56 }
57
58 pub fn as_str(&self) -> &str {
60 self.0.as_str()
61 }
62
63 pub fn from_str_unchecked(name: &'name str) -> Self {
68 Self(Str::from(name))
69 }
70
71 pub fn from_static_str(name: &'static str) -> Result<Self> {
73 ensure_correct_error_name(name)?;
74 Ok(Self(Str::from_static(name)))
75 }
76
77 pub const fn from_static_str_unchecked(name: &'static str) -> Self {
79 Self(Str::from_static(name))
80 }
81
82 pub fn from_string_unchecked(name: String) -> Self {
87 Self(Str::from(name))
88 }
89
90 pub fn to_owned(&self) -> ErrorName<'static> {
92 ErrorName(self.0.to_owned())
93 }
94
95 pub fn into_owned(self) -> ErrorName<'static> {
97 ErrorName(self.0.into_owned())
98 }
99}
100
101impl Deref for ErrorName<'_> {
102 type Target = str;
103
104 fn deref(&self) -> &Self::Target {
105 self.as_str()
106 }
107}
108
109impl Borrow<str> for ErrorName<'_> {
110 fn borrow(&self) -> &str {
111 self.as_str()
112 }
113}
114
115impl Display for ErrorName<'_> {
116 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117 Display::fmt(&self.as_str(), f)
118 }
119}
120
121impl PartialEq<str> for ErrorName<'_> {
122 fn eq(&self, other: &str) -> bool {
123 self.as_str() == other
124 }
125}
126
127impl PartialEq<&str> for ErrorName<'_> {
128 fn eq(&self, other: &&str) -> bool {
129 self.as_str() == *other
130 }
131}
132
133impl PartialEq<OwnedErrorName> for ErrorName<'_> {
134 fn eq(&self, other: &OwnedErrorName) -> bool {
135 *self == other.0
136 }
137}
138
139impl<'de: 'name, 'name> Deserialize<'de> for ErrorName<'name> {
140 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
141 where
142 D: serde::Deserializer<'de>,
143 {
144 let name = <Cow<'name, str>>::deserialize(deserializer)?;
145
146 Self::try_from(name).map_err(|e| de::Error::custom(e.to_string()))
147 }
148}
149
150impl_try_from! {
151 ty: ErrorName<'s>,
152 owned_ty: OwnedErrorName,
153 validate_fn: ensure_correct_error_name,
154 try_from: [&'s str, String, Arc<str>, Cow<'s, str>, Str<'s>],
155}
156
157fn ensure_correct_error_name(name: &str) -> Result<()> {
158 if name.len() < 3 {
168 return Err(Error::InvalidErrorName(format!(
169 "`{}` is {} characters long, which is smaller than minimum allowed (3)",
170 name,
171 name.len(),
172 )));
173 } else if name.len() > 255 {
174 return Err(Error::InvalidErrorName(format!(
175 "`{}` is {} characters long, which is longer than maximum allowed (255)",
176 name,
177 name.len(),
178 )));
179 }
180
181 let mut prev = None;
182 let mut no_dot = true;
183 for c in name.chars() {
184 if c == '.' {
185 if prev.is_none() || prev == Some('.') {
186 return Err(Error::InvalidErrorName(String::from(
187 "must not contain a double `.`",
188 )));
189 }
190
191 if no_dot {
192 no_dot = false;
193 }
194 } else if c.is_ascii_digit() && (prev.is_none() || prev == Some('.')) {
195 return Err(Error::InvalidErrorName(String::from(
196 "each element must not start with a digit",
197 )));
198 } else if !c.is_ascii_alphanumeric() && c != '_' {
199 return Err(Error::InvalidErrorName(format!(
200 "`{c}` character not allowed"
201 )));
202 }
203
204 prev = Some(c);
205 }
206
207 if no_dot {
208 return Err(Error::InvalidErrorName(String::from(
209 "must contain at least 1 `.`",
210 )));
211 }
212
213 Ok(())
214}
215
216impl TryFrom<()> for ErrorName<'_> {
219 type Error = Error;
220
221 fn try_from(_value: ()) -> Result<Self> {
222 unreachable!("Conversion from `()` is not meant to actually work");
223 }
224}
225
226impl<'name> From<&ErrorName<'name>> for ErrorName<'name> {
227 fn from(name: &ErrorName<'name>) -> Self {
228 name.clone()
229 }
230}
231
232impl<'name> From<ErrorName<'name>> for Str<'name> {
233 fn from(value: ErrorName<'name>) -> Self {
234 value.0
235 }
236}
237
238impl<'name> NoneValue for ErrorName<'name> {
239 type NoneType = &'name str;
240
241 fn null_value() -> Self::NoneType {
242 <&str>::default()
243 }
244}
245
246#[derive(Clone, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue)]
248pub struct OwnedErrorName(#[serde(borrow)] ErrorName<'static>);
249
250assert_impl_all!(OwnedErrorName: Send, Sync, Unpin);
251
252impl_str_basic!(OwnedErrorName);
253
254impl OwnedErrorName {
255 pub fn into_inner(self) -> ErrorName<'static> {
257 self.0
258 }
259
260 pub fn inner(&self) -> &ErrorName<'static> {
262 &self.0
263 }
264}
265
266impl Deref for OwnedErrorName {
267 type Target = ErrorName<'static>;
268
269 fn deref(&self) -> &Self::Target {
270 &self.0
271 }
272}
273
274impl Borrow<str> for OwnedErrorName {
275 fn borrow(&self) -> &str {
276 self.0.as_str()
277 }
278}
279
280impl From<OwnedErrorName> for ErrorName<'_> {
281 fn from(o: OwnedErrorName) -> Self {
282 o.into_inner()
283 }
284}
285
286impl<'unowned, 'owned: 'unowned> From<&'owned OwnedErrorName> for ErrorName<'unowned> {
287 fn from(name: &'owned OwnedErrorName) -> Self {
288 ErrorName::from_str_unchecked(name.as_str())
289 }
290}
291
292impl From<ErrorName<'_>> for OwnedErrorName {
293 fn from(name: ErrorName<'_>) -> Self {
294 OwnedErrorName(name.into_owned())
295 }
296}
297
298impl From<OwnedErrorName> for Str<'_> {
299 fn from(value: OwnedErrorName) -> Self {
300 value.into_inner().0
301 }
302}
303
304impl<'de> Deserialize<'de> for OwnedErrorName {
305 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
306 where
307 D: de::Deserializer<'de>,
308 {
309 String::deserialize(deserializer)
310 .and_then(|n| ErrorName::try_from(n).map_err(|e| de::Error::custom(e.to_string())))
311 .map(Self)
312 }
313}
314
315impl PartialEq<&str> for OwnedErrorName {
316 fn eq(&self, other: &&str) -> bool {
317 self.as_str() == *other
318 }
319}
320
321impl PartialEq<ErrorName<'_>> for OwnedErrorName {
322 fn eq(&self, other: &ErrorName<'_>) -> bool {
323 self.0 == *other
324 }
325}
326
327impl Debug for OwnedErrorName {
328 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
329 f.debug_tuple("OwnedErrorName")
330 .field(&self.as_str())
331 .finish()
332 }
333}
334
335impl Display for OwnedErrorName {
336 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
337 Display::fmt(&ErrorName::from(self), f)
338 }
339}
340
341impl NoneValue for OwnedErrorName {
342 type NoneType = <ErrorName<'static> as NoneValue>::NoneType;
343
344 fn null_value() -> Self::NoneType {
345 ErrorName::null_value()
346 }
347}