zbus_names/
member_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 [member (method or signal) name][in] on the bus.
16///
17/// # Examples
18///
19/// ```
20/// use zbus_names::MemberName;
21///
22/// // Valid member names.
23/// let name = MemberName::try_from("Member_for_you").unwrap();
24/// assert_eq!(name, "Member_for_you");
25/// let name = MemberName::try_from("CamelCase101").unwrap();
26/// assert_eq!(name, "CamelCase101");
27/// let name = MemberName::try_from("a_very_loooooooooooooooooo_ooooooo_0000o0ngName").unwrap();
28/// assert_eq!(name, "a_very_loooooooooooooooooo_ooooooo_0000o0ngName");
29///
30/// // Invalid member names
31/// MemberName::try_from("").unwrap_err();
32/// MemberName::try_from(".").unwrap_err();
33/// MemberName::try_from("1startWith_a_Digit").unwrap_err();
34/// MemberName::try_from("contains.dots_in_the_name").unwrap_err();
35/// MemberName::try_from("contains-dashes-in_the_name").unwrap_err();
36/// ```
37///
38/// [in]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-member
39#[derive(
40    Clone, Debug, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue,
41)]
42pub struct MemberName<'name>(Str<'name>);
43
44assert_impl_all!(MemberName<'_>: Send, Sync, Unpin);
45
46impl_str_basic!(MemberName<'_>);
47
48impl<'name> MemberName<'name> {
49    /// This is faster than `Clone::clone` when `self` contains owned data.
50    pub fn as_ref(&self) -> MemberName<'_> {
51        MemberName(self.0.as_ref())
52    }
53
54    /// The member name as string.
55    pub fn as_str(&self) -> &str {
56        self.0.as_str()
57    }
58
59    /// Create a new `MemberName` from the given string.
60    ///
61    /// Since the passed string is not checked for correctness, prefer using the
62    /// `TryFrom<&str>` implementation.
63    pub fn from_str_unchecked(name: &'name str) -> Self {
64        Self(Str::from(name))
65    }
66
67    /// Same as `try_from`, except it takes a `&'static str`.
68    pub fn from_static_str(name: &'static str) -> Result<Self> {
69        validate(name)?;
70        Ok(Self(Str::from_static(name)))
71    }
72
73    /// Same as `from_str_unchecked`, except it takes a `&'static str`.
74    pub const fn from_static_str_unchecked(name: &'static str) -> Self {
75        Self(Str::from_static(name))
76    }
77
78    /// Same as `from_str_unchecked`, except it takes an owned `String`.
79    ///
80    /// Since the passed string is not checked for correctness, prefer using the
81    /// `TryFrom<String>` implementation.
82    pub fn from_string_unchecked(name: String) -> Self {
83        Self(Str::from(name))
84    }
85
86    /// Creates an owned clone of `self`.
87    pub fn to_owned(&self) -> MemberName<'static> {
88        MemberName(self.0.to_owned())
89    }
90
91    /// Creates an owned clone of `self`.
92    pub fn into_owned(self) -> MemberName<'static> {
93        MemberName(self.0.into_owned())
94    }
95}
96
97impl Deref for MemberName<'_> {
98    type Target = str;
99
100    fn deref(&self) -> &Self::Target {
101        self.as_str()
102    }
103}
104
105impl Borrow<str> for MemberName<'_> {
106    fn borrow(&self) -> &str {
107        self.as_str()
108    }
109}
110
111impl Display for MemberName<'_> {
112    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
113        Display::fmt(&self.as_str(), f)
114    }
115}
116
117impl PartialEq<str> for MemberName<'_> {
118    fn eq(&self, other: &str) -> bool {
119        self.as_str() == other
120    }
121}
122
123impl PartialEq<&str> for MemberName<'_> {
124    fn eq(&self, other: &&str) -> bool {
125        self.as_str() == *other
126    }
127}
128
129impl PartialEq<OwnedMemberName> for MemberName<'_> {
130    fn eq(&self, other: &OwnedMemberName) -> bool {
131        *self == other.0
132    }
133}
134
135impl<'de: 'name, 'name> Deserialize<'de> for MemberName<'name> {
136    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
137    where
138        D: serde::Deserializer<'de>,
139    {
140        let name = <Cow<'name, str>>::deserialize(deserializer)?;
141
142        Self::try_from(name).map_err(|e| de::Error::custom(e.to_string()))
143    }
144}
145
146impl<'name> From<MemberName<'name>> for Str<'name> {
147    fn from(value: MemberName<'name>) -> Self {
148        value.0
149    }
150}
151
152impl_try_from! {
153    ty: MemberName<'s>,
154    owned_ty: OwnedMemberName,
155    validate_fn: validate,
156    try_from: [&'s str, String, Arc<str>, Cow<'s, str>, Str<'s>],
157}
158
159fn validate(name: &str) -> Result<()> {
160    validate_bytes(name.as_bytes()).map_err(|_| {
161        Error::InvalidName(
162            "Invalid member name. See \
163            https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-member",
164        )
165    })
166}
167
168pub(crate) fn validate_bytes(bytes: &[u8]) -> std::result::Result<(), ()> {
169    use winnow::{
170        stream::AsChar,
171        token::{one_of, take_while},
172        Parser,
173    };
174    // Rules
175    //
176    // * Only ASCII alphanumeric or `_`.
177    // * Must not begin with a digit.
178    // * Must contain at least 1 character.
179    // * <= 255 characters.
180    let first_element_char = one_of((AsChar::is_alpha, b'_'));
181    let subsequent_element_chars = take_while::<_, _, ()>(0.., (AsChar::is_alphanum, b'_'));
182    let mut member_name = (first_element_char, subsequent_element_chars);
183
184    member_name.parse(bytes).map_err(|_| ()).and_then(|_| {
185        // Least likely scenario so we check this last.
186        if bytes.len() > 255 {
187            return Err(());
188        }
189
190        Ok(())
191    })
192}
193
194/// This never succeeds but is provided so it's easier to pass `Option::None` values for API
195/// requiring `Option<TryInto<impl BusName>>`, since type inference won't work here.
196impl TryFrom<()> for MemberName<'_> {
197    type Error = Error;
198
199    fn try_from(_value: ()) -> Result<Self> {
200        unreachable!("Conversion from `()` is not meant to actually work");
201    }
202}
203
204impl<'name> From<&MemberName<'name>> for MemberName<'name> {
205    fn from(name: &MemberName<'name>) -> Self {
206        name.clone()
207    }
208}
209
210impl<'name> NoneValue for MemberName<'name> {
211    type NoneType = &'name str;
212
213    fn null_value() -> Self::NoneType {
214        <&str>::default()
215    }
216}
217
218/// Owned sibling of [`MemberName`].
219#[derive(Clone, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue)]
220pub struct OwnedMemberName(#[serde(borrow)] MemberName<'static>);
221
222assert_impl_all!(OwnedMemberName: Send, Sync, Unpin);
223
224impl_str_basic!(OwnedMemberName);
225
226impl OwnedMemberName {
227    /// Convert to the inner `MemberName`, consuming `self`.
228    pub fn into_inner(self) -> MemberName<'static> {
229        self.0
230    }
231
232    /// Get a reference to the inner `MemberName`.
233    pub fn inner(&self) -> &MemberName<'static> {
234        &self.0
235    }
236}
237
238impl Deref for OwnedMemberName {
239    type Target = MemberName<'static>;
240
241    fn deref(&self) -> &Self::Target {
242        &self.0
243    }
244}
245
246impl Borrow<str> for OwnedMemberName {
247    fn borrow(&self) -> &str {
248        self.0.as_str()
249    }
250}
251
252impl From<OwnedMemberName> for MemberName<'_> {
253    fn from(o: OwnedMemberName) -> Self {
254        o.into_inner()
255    }
256}
257
258impl<'unowned, 'owned: 'unowned> From<&'owned OwnedMemberName> for MemberName<'unowned> {
259    fn from(name: &'owned OwnedMemberName) -> Self {
260        MemberName::from_str_unchecked(name.as_str())
261    }
262}
263
264impl From<MemberName<'_>> for OwnedMemberName {
265    fn from(name: MemberName<'_>) -> Self {
266        OwnedMemberName(name.into_owned())
267    }
268}
269
270impl From<OwnedMemberName> for Str<'_> {
271    fn from(value: OwnedMemberName) -> Self {
272        value.into_inner().0
273    }
274}
275
276impl<'de> Deserialize<'de> for OwnedMemberName {
277    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
278    where
279        D: de::Deserializer<'de>,
280    {
281        String::deserialize(deserializer)
282            .and_then(|n| MemberName::try_from(n).map_err(|e| de::Error::custom(e.to_string())))
283            .map(Self)
284    }
285}
286
287impl PartialEq<&str> for OwnedMemberName {
288    fn eq(&self, other: &&str) -> bool {
289        self.as_str() == *other
290    }
291}
292
293impl PartialEq<MemberName<'_>> for OwnedMemberName {
294    fn eq(&self, other: &MemberName<'_>) -> bool {
295        self.0 == *other
296    }
297}
298
299impl Debug for OwnedMemberName {
300    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
301        f.debug_tuple("OwnedMemberName")
302            .field(&self.as_str())
303            .finish()
304    }
305}
306
307impl Display for OwnedMemberName {
308    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
309        Display::fmt(&MemberName::from(self), f)
310    }
311}
312
313impl NoneValue for OwnedMemberName {
314    type NoneType = <MemberName<'static> as NoneValue>::NoneType;
315
316    fn null_value() -> Self::NoneType {
317        MemberName::null_value()
318    }
319}