1use crate::{utils::impl_try_from, Error, Result};
2use serde::{de, Deserialize, Serialize};
3use static_assertions::assert_impl_all;
4use std::{
5 borrow::{Borrow, Cow},
6 convert::TryFrom,
7 fmt::{self, Display, Formatter},
8 ops::Deref,
9 sync::Arc,
10};
11use zvariant::{NoneValue, OwnedValue, Str, Type, Value};
12
13/// String that identifies an [error name][en] on the bus.
14///
15/// Error names have same constraints as error names.
16///
17/// # Examples
18///
19/// ```
20/// use core::convert::TryFrom;
21/// use zbus_names::ErrorName;
22///
23/// // Valid error names.
24/// let name = ErrorName::try_from("org.gnome.Error_for_you").unwrap();
25/// assert_eq!(name, "org.gnome.Error_for_you");
26/// let name = ErrorName::try_from("a.very.loooooooooooooooooo_ooooooo_0000o0ng.ErrorName").unwrap();
27/// assert_eq!(name, "a.very.loooooooooooooooooo_ooooooo_0000o0ng.ErrorName");
28///
29/// // Invalid error names
30/// ErrorName::try_from("").unwrap_err();
31/// ErrorName::try_from(":start.with.a.colon").unwrap_err();
32/// ErrorName::try_from("double..dots").unwrap_err();
33/// ErrorName::try_from(".").unwrap_err();
34/// ErrorName::try_from(".start.with.dot").unwrap_err();
35/// ErrorName::try_from("no-dots").unwrap_err();
36/// ErrorName::try_from("1st.element.starts.with.digit").unwrap_err();
37/// ErrorName::try_from("the.2nd.element.starts.with.digit").unwrap_err();
38/// ErrorName::try_from("contains.dashes-in.the.name").unwrap_err();
39/// ```
40///
41/// [en]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-error
42#[derive(
43 Clone, Debug, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue,
44)]
45pub struct ErrorName<'name>(Str<'name>);
46
47assert_impl_all!(ErrorName<'_>: Send, Sync, Unpin);
48
49impl<'name> ErrorName<'name> {
50 /// A borrowed clone (never allocates, unlike clone).
51 pub fn as_ref(&self) -> ErrorName<'_> {
52 ErrorName(self.0.as_ref())
53 }
54
55 /// The error name as string.
56 pub fn as_str(&self) -> &str {
57 self.0.as_str()
58 }
59
60 /// Create a new `ErrorName` from the given string.
61 ///
62 /// Since the passed string is not checked for correctness, prefer using the
63 /// `TryFrom<&str>` implementation.
64 pub fn from_str_unchecked(name: &'name str) -> Self {
65 Self(Str::from(name))
66 }
67
68 /// Same as `try_from`, except it takes a `&'static str`.
69 pub fn from_static_str(name: &'static str) -> Result<Self> {
70 ensure_correct_error_name(name)?;
71 Ok(Self(Str::from_static(name)))
72 }
73
74 /// Same as `from_str_unchecked`, except it takes a `&'static str`.
75 pub const fn from_static_str_unchecked(name: &'static str) -> Self {
76 Self(Str::from_static(name))
77 }
78
79 /// Same as `from_str_unchecked`, except it takes an owned `String`.
80 ///
81 /// Since the passed string is not checked for correctness, prefer using the
82 /// `TryFrom<String>` implementation.
83 pub fn from_string_unchecked(name: String) -> Self {
84 Self(Str::from(name))
85 }
86
87 /// Creates an owned clone of `self`.
88 pub fn to_owned(&self) -> ErrorName<'static> {
89 ErrorName(self.0.to_owned())
90 }
91
92 /// Creates an owned clone of `self`.
93 pub fn into_owned(self) -> ErrorName<'static> {
94 ErrorName(self.0.into_owned())
95 }
96}
97
98impl Deref for ErrorName<'_> {
99 type Target = str;
100
101 fn deref(&self) -> &Self::Target {
102 self.as_str()
103 }
104}
105
106impl Borrow<str> for ErrorName<'_> {
107 fn borrow(&self) -> &str {
108 self.as_str()
109 }
110}
111
112impl Display for ErrorName<'_> {
113 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
114 Display::fmt(&self.as_str(), f)
115 }
116}
117
118impl PartialEq<str> for ErrorName<'_> {
119 fn eq(&self, other: &str) -> bool {
120 self.as_str() == other
121 }
122}
123
124impl PartialEq<&str> for ErrorName<'_> {
125 fn eq(&self, other: &&str) -> bool {
126 self.as_str() == *other
127 }
128}
129
130impl PartialEq<OwnedErrorName> for ErrorName<'_> {
131 fn eq(&self, other: &OwnedErrorName) -> bool {
132 *self == other.0
133 }
134}
135
136impl<'de: 'name, 'name> Deserialize<'de> for ErrorName<'name> {
137 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
138 where
139 D: serde::Deserializer<'de>,
140 {
141 let name: Cow<'_, str> = <Cow<'name, str>>::deserialize(deserializer)?;
142
143 Self::try_from(name).map_err(|e: Error| de::Error::custom(msg:e.to_string()))
144 }
145}
146
147impl_try_from! {
148 ty: ErrorName<'s>,
149 owned_ty: OwnedErrorName,
150 validate_fn: ensure_correct_error_name,
151 try_from: [&'s str, String, Arc<str>, Cow<'s, str>, Str<'s>],
152}
153
154fn ensure_correct_error_name(name: &str) -> Result<()> {
155 // Rules
156 //
157 // * Only ASCII alphanumeric or `_`.
158 // * Must not begin with a `.`.
159 // * Must contain at least one `.`.
160 // * Each element must:
161 // * not begin with a digit.
162 // * be 1 character (so name must be minimum 3 characters long).
163 // * <= 255 characters.
164 if name.len() < 3 {
165 return Err(Error::InvalidErrorName(format!(
166 "`{}` is {} characters long, which is smaller than minimum allowed (3)",
167 name,
168 name.len(),
169 )));
170 } else if name.len() > 255 {
171 return Err(Error::InvalidErrorName(format!(
172 "`{}` is {} characters long, which is longer than maximum allowed (255)",
173 name,
174 name.len(),
175 )));
176 }
177
178 let mut prev = None;
179 let mut no_dot = true;
180 for c in name.chars() {
181 if c == '.' {
182 if prev.is_none() || prev == Some('.') {
183 return Err(Error::InvalidErrorName(String::from(
184 "must not contain a double `.`",
185 )));
186 }
187
188 if no_dot {
189 no_dot = false;
190 }
191 } else if c.is_ascii_digit() && (prev.is_none() || prev == Some('.')) {
192 return Err(Error::InvalidErrorName(String::from(
193 "each element must not start with a digit",
194 )));
195 } else if !c.is_ascii_alphanumeric() && c != '_' {
196 return Err(Error::InvalidErrorName(format!(
197 "`{c}` character not allowed"
198 )));
199 }
200
201 prev = Some(c);
202 }
203
204 if no_dot {
205 return Err(Error::InvalidErrorName(String::from(
206 "must contain at least 1 `.`",
207 )));
208 }
209
210 Ok(())
211}
212
213/// This never succeeds but is provided so it's easier to pass `Option::None` values for API
214/// requiring `Option<TryInto<impl BusName>>`, since type inference won't work here.
215impl TryFrom<()> for ErrorName<'_> {
216 type Error = Error;
217
218 fn try_from(_value: ()) -> Result<Self> {
219 unreachable!("Conversion from `()` is not meant to actually work");
220 }
221}
222
223impl<'name> From<&ErrorName<'name>> for ErrorName<'name> {
224 fn from(name: &ErrorName<'name>) -> Self {
225 name.clone()
226 }
227}
228
229impl<'name> From<ErrorName<'name>> for Str<'name> {
230 fn from(value: ErrorName<'name>) -> Self {
231 value.0
232 }
233}
234
235impl<'name> NoneValue for ErrorName<'name> {
236 type NoneType = &'name str;
237
238 fn null_value() -> Self::NoneType {
239 <&str>::default()
240 }
241}
242
243/// Owned sibling of [`ErrorName`].
244#[derive(
245 Clone, Debug, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue,
246)]
247pub struct OwnedErrorName(#[serde(borrow)] ErrorName<'static>);
248
249assert_impl_all!(OwnedErrorName: Send, Sync, Unpin);
250
251impl OwnedErrorName {
252 /// Convert to the inner `ErrorName`, consuming `self`.
253 pub fn into_inner(self) -> ErrorName<'static> {
254 self.0
255 }
256
257 /// Get a reference to the inner `ErrorName`.
258 pub fn inner(&self) -> &ErrorName<'static> {
259 &self.0
260 }
261}
262
263impl Deref for OwnedErrorName {
264 type Target = ErrorName<'static>;
265
266 fn deref(&self) -> &Self::Target {
267 &self.0
268 }
269}
270
271impl Borrow<str> for OwnedErrorName {
272 fn borrow(&self) -> &str {
273 self.0.as_str()
274 }
275}
276
277impl From<OwnedErrorName> for ErrorName<'static> {
278 fn from(o: OwnedErrorName) -> Self {
279 o.into_inner()
280 }
281}
282
283impl<'unowned, 'owned: 'unowned> From<&'owned OwnedErrorName> for ErrorName<'unowned> {
284 fn from(name: &'owned OwnedErrorName) -> Self {
285 ErrorName::from_str_unchecked(name:name.as_str())
286 }
287}
288
289impl From<ErrorName<'_>> for OwnedErrorName {
290 fn from(name: ErrorName<'_>) -> Self {
291 OwnedErrorName(name.into_owned())
292 }
293}
294
295impl From<OwnedErrorName> for Str<'static> {
296 fn from(value: OwnedErrorName) -> Self {
297 value.into_inner().0
298 }
299}
300
301impl<'de> Deserialize<'de> for OwnedErrorName {
302 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
303 where
304 D: de::Deserializer<'de>,
305 {
306 String::deserialize(deserializer)
307 .and_then(|n| ErrorName::try_from(n).map_err(|e| de::Error::custom(e.to_string())))
308 .map(Self)
309 }
310}
311
312impl PartialEq<&str> for OwnedErrorName {
313 fn eq(&self, other: &&str) -> bool {
314 self.as_str() == *other
315 }
316}
317
318impl PartialEq<ErrorName<'_>> for OwnedErrorName {
319 fn eq(&self, other: &ErrorName<'_>) -> bool {
320 self.0 == *other
321 }
322}
323
324impl Display for OwnedErrorName {
325 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
326 ErrorName::from(self).fmt(f)
327 }
328}
329
330impl NoneValue for OwnedErrorName {
331 type NoneType = <ErrorName<'static> as NoneValue>::NoneType;
332
333 fn null_value() -> Self::NoneType {
334 ErrorName::null_value()
335 }
336}
337