zbus_names/
unique_name.rs

1use crate::{Error, Result, utils::define_name_type_impls};
2use serde::Serialize;
3use zvariant::{OwnedValue, Str, Type, Value};
4
5/// String that identifies a [unique bus name][ubn].
6///
7/// # Examples
8///
9/// ```
10/// use zbus_names::UniqueName;
11///
12/// // Valid unique names.
13/// let name = UniqueName::try_from(":org.gnome.Service-for_you").unwrap();
14/// assert_eq!(name, ":org.gnome.Service-for_you");
15/// let name = UniqueName::try_from(":a.very.loooooooooooooooooo-ooooooo_0000o0ng.Name").unwrap();
16/// assert_eq!(name, ":a.very.loooooooooooooooooo-ooooooo_0000o0ng.Name");
17///
18/// // Invalid unique names
19/// UniqueName::try_from("").unwrap_err();
20/// UniqueName::try_from("dont.start.with.a.colon").unwrap_err();
21/// UniqueName::try_from(":double..dots").unwrap_err();
22/// UniqueName::try_from(".").unwrap_err();
23/// UniqueName::try_from(".start.with.dot").unwrap_err();
24/// UniqueName::try_from(":no-dots").unwrap_err();
25/// ```
26///
27/// [ubn]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus
28#[derive(
29    Clone, Debug, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue,
30)]
31pub struct UniqueName<'name>(pub(crate) Str<'name>);
32
33/// Owned sibling of [`UniqueName`].
34#[derive(Clone, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue)]
35pub struct OwnedUniqueName(#[serde(borrow)] UniqueName<'static>);
36
37define_name_type_impls! {
38    name: UniqueName,
39    owned: OwnedUniqueName,
40    validate: validate,
41}
42
43fn validate(name: &str) -> Result<()> {
44    validate_bytes(name.as_bytes()).map_err(|_| {
45        Error::InvalidName(
46            "Invalid unique name. \
47            See https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus"
48        )
49    })
50}
51
52pub(crate) fn validate_bytes(bytes: &[u8]) -> std::result::Result<(), ()> {
53    use winnow::{
54        Parser,
55        combinator::{alt, separated},
56        stream::AsChar,
57        token::take_while,
58    };
59    // Rules
60    //
61    // * Only ASCII alphanumeric, `_` or '-'
62    // * Must begin with a `:`.
63    // * Must contain at least one `.`.
64    // * Each element must be 1 character (so name must be minimum 4 characters long).
65    // * <= 255 characters.
66    let element = take_while::<_, _, ()>(1.., (AsChar::is_alphanum, b'_', b'-'));
67    let peer_name = (b':', (separated(2.., element, b'.'))).map(|_: (_, ())| ());
68    let bus_name = b"org.freedesktop.DBus".map(|_| ());
69    let mut unique_name = alt((bus_name, peer_name));
70
71    unique_name.parse(bytes).map_err(|_| ()).and_then(|_: ()| {
72        // Least likely scenario so we check this last.
73        if bytes.len() > 255 {
74            return Err(());
75        }
76
77        Ok(())
78    })
79}