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}