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