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