zbus_names/
error_name.rs

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/// String that identifies an [error name][en] on the bus.
16///
17/// Error names have same constraints as error names.
18///
19/// # Examples
20///
21/// ```
22/// use zbus_names::ErrorName;
23///
24/// // Valid error names.
25/// let name = ErrorName::try_from("org.gnome.Error_for_you").unwrap();
26/// assert_eq!(name, "org.gnome.Error_for_you");
27/// let name = ErrorName::try_from("a.very.loooooooooooooooooo_ooooooo_0000o0ng.ErrorName").unwrap();
28/// assert_eq!(name, "a.very.loooooooooooooooooo_ooooooo_0000o0ng.ErrorName");
29///
30/// // Invalid error names
31/// ErrorName::try_from("").unwrap_err();
32/// ErrorName::try_from(":start.with.a.colon").unwrap_err();
33/// ErrorName::try_from("double..dots").unwrap_err();
34/// ErrorName::try_from(".").unwrap_err();
35/// ErrorName::try_from(".start.with.dot").unwrap_err();
36/// ErrorName::try_from("no-dots").unwrap_err();
37/// ErrorName::try_from("1st.element.starts.with.digit").unwrap_err();
38/// ErrorName::try_from("the.2nd.element.starts.with.digit").unwrap_err();
39/// ErrorName::try_from("contains.dashes-in.the.name").unwrap_err();
40/// ```
41///
42/// [en]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-error
43#[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    /// This is faster than `Clone::clone` when `self` contains owned data.
54    pub fn as_ref(&self) -> ErrorName<'_> {
55        ErrorName(self.0.as_ref())
56    }
57
58    /// The error name as string.
59    pub fn as_str(&self) -> &str {
60        self.0.as_str()
61    }
62
63    /// Create a new `ErrorName` from the given string.
64    ///
65    /// Since the passed string is not checked for correctness, prefer using the
66    /// `TryFrom<&str>` implementation.
67    pub fn from_str_unchecked(name: &'name str) -> Self {
68        Self(Str::from(name))
69    }
70
71    /// Same as `try_from`, except it takes a `&'static str`.
72    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    /// Same as `from_str_unchecked`, except it takes a `&'static str`.
78    pub const fn from_static_str_unchecked(name: &'static str) -> Self {
79        Self(Str::from_static(name))
80    }
81
82    /// Same as `from_str_unchecked`, except it takes an owned `String`.
83    ///
84    /// Since the passed string is not checked for correctness, prefer using the
85    /// `TryFrom<String>` implementation.
86    pub fn from_string_unchecked(name: String) -> Self {
87        Self(Str::from(name))
88    }
89
90    /// Creates an owned clone of `self`.
91    pub fn to_owned(&self) -> ErrorName<'static> {
92        ErrorName(self.0.to_owned())
93    }
94
95    /// Creates an owned clone of `self`.
96    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    // Rules
159    //
160    // * Only ASCII alphanumeric or `_`.
161    // * Must not begin with a `.`.
162    // * Must contain at least one `.`.
163    // * Each element must:
164    //   * not begin with a digit.
165    //   * be 1 character (so name must be minimum 3 characters long).
166    // * <= 255 characters.
167    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
216/// This never succeeds but is provided so it's easier to pass `Option::None` values for API
217/// requiring `Option<TryInto<impl BusName>>`, since type inference won't work here.
218impl 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/// Owned sibling of [`ErrorName`].
247#[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    /// Convert to the inner `ErrorName`, consuming `self`.
256    pub fn into_inner(self) -> ErrorName<'static> {
257        self.0
258    }
259
260    /// Get a reference to the inner `ErrorName`.
261    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}