zbus_names/member_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 an [member (method or signal) name][in] on the bus.
6///
7/// # Examples
8///
9/// ```
10/// use zbus_names::MemberName;
11///
12/// // Valid member names.
13/// let name = MemberName::try_from("Member_for_you").unwrap();
14/// assert_eq!(name, "Member_for_you");
15/// let name = MemberName::try_from("CamelCase101").unwrap();
16/// assert_eq!(name, "CamelCase101");
17/// let name = MemberName::try_from("a_very_loooooooooooooooooo_ooooooo_0000o0ngName").unwrap();
18/// assert_eq!(name, "a_very_loooooooooooooooooo_ooooooo_0000o0ngName");
19///
20/// // Invalid member names
21/// MemberName::try_from("").unwrap_err();
22/// MemberName::try_from(".").unwrap_err();
23/// MemberName::try_from("1startWith_a_Digit").unwrap_err();
24/// MemberName::try_from("contains.dots_in_the_name").unwrap_err();
25/// MemberName::try_from("contains-dashes-in_the_name").unwrap_err();
26/// ```
27///
28/// [in]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-member
29#[derive(
30 Clone, Debug, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue,
31)]
32pub struct MemberName<'name>(Str<'name>);
33
34/// Owned sibling of [`MemberName`].
35#[derive(Clone, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue)]
36pub struct OwnedMemberName(#[serde(borrow)] MemberName<'static>);
37
38define_name_type_impls! {
39 name: MemberName,
40 owned: OwnedMemberName,
41 validate: validate,
42}
43
44fn validate(name: &str) -> Result<()> {
45 validate_bytes(name.as_bytes()).map_err(|_| {
46 Error::InvalidName(
47 "Invalid member name. See \
48 https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-member",
49 )
50 })
51}
52
53pub(crate) fn validate_bytes(bytes: &[u8]) -> std::result::Result<(), ()> {
54 use winnow::{
55 Parser,
56 stream::AsChar,
57 token::{one_of, take_while},
58 };
59 // Rules
60 //
61 // * Only ASCII alphanumeric or `_`.
62 // * Must not begin with a digit.
63 // * Must contain at least 1 character.
64 // * <= 255 characters.
65 let first_element_char = one_of((AsChar::is_alpha, b'_'));
66 let subsequent_element_chars = take_while::<_, _, ()>(0.., (AsChar::is_alphanum, b'_'));
67 let mut member_name = (first_element_char, subsequent_element_chars);
68
69 member_name.parse(bytes).map_err(|_| ()).and_then(|_| {
70 // Least likely scenario so we check this last.
71 if bytes.len() > 255 {
72 return Err(());
73 }
74
75 Ok(())
76 })
77}