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 ensure_correct_interface_name(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> = <Cow<'name, str>>::deserialize(deserializer)?;
143
144 Self::try_from(name).map_err(|e: Error| de::Error::custom(msg:e.to_string()))
145 }
146}
147
148impl_try_from! {
149 ty:InterfaceName<'s>,
150 owned_ty: OwnedInterfaceName,
151 validate_fn: ensure_correct_interface_name,
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 ensure_correct_interface_name(name: &str) -> Result<()> {
162 // Rules
163 //
164 // * Only ASCII alphanumeric or `_`.
165 // * Must not begin with a `.`.
166 // * Must contain at least one `.`.
167 // * Each element must:
168 // * not begin with a digit.
169 // * be 1 character (so name must be minimum 3 characters long).
170 // * <= 255 characters.
171 if name.len() < 3 {
172 return Err(Error::InvalidInterfaceName(format!(
173 "`{}` is {} characters long, which is smaller than minimum allowed (3)",
174 name,
175 name.len(),
176 )));
177 } else if name.len() > 255 {
178 return Err(Error::InvalidInterfaceName(format!(
179 "`{}` is {} characters long, which is longer than maximum allowed (255)",
180 name,
181 name.len(),
182 )));
183 }
184
185 let mut prev = None;
186 let mut no_dot = true;
187 for c in name.chars() {
188 if c == '.' {
189 if prev.is_none() || prev == Some('.') {
190 return Err(Error::InvalidInterfaceName(String::from(
191 "must not contain a double `.`",
192 )));
193 }
194
195 if no_dot {
196 no_dot = false;
197 }
198 } else if c.is_ascii_digit() && (prev.is_none() || prev == Some('.')) {
199 return Err(Error::InvalidInterfaceName(String::from(
200 "each element must not start with a digit",
201 )));
202 } else if !c.is_ascii_alphanumeric() && c != '_' {
203 return Err(Error::InvalidInterfaceName(format!(
204 "`{c}` character not allowed"
205 )));
206 }
207
208 prev = Some(c);
209 }
210
211 if no_dot {
212 return Err(Error::InvalidInterfaceName(String::from(
213 "must contain at least 1 `.`",
214 )));
215 }
216
217 Ok(())
218}
219
220/// This never succeeds but is provided so it's easier to pass `Option::None` values for API
221/// requiring `Option<TryInto<impl BusName>>`, since type inference won't work here.
222impl TryFrom<()> for InterfaceName<'_> {
223 type Error = Error;
224
225 fn try_from(_value: ()) -> Result<Self> {
226 unreachable!("Conversion from `()` is not meant to actually work");
227 }
228}
229
230impl<'name> From<&InterfaceName<'name>> for InterfaceName<'name> {
231 fn from(name: &InterfaceName<'name>) -> Self {
232 name.clone()
233 }
234}
235
236impl<'name> NoneValue for InterfaceName<'name> {
237 type NoneType = &'name str;
238
239 fn null_value() -> Self::NoneType {
240 <&str>::default()
241 }
242}
243
244/// Owned sibling of [`InterfaceName`].
245#[derive(Clone, Hash, PartialEq, Eq, Serialize, Type, Value, PartialOrd, Ord, OwnedValue)]
246pub struct OwnedInterfaceName(#[serde(borrow)] InterfaceName<'static>);
247
248assert_impl_all!(OwnedInterfaceName: Send, Sync, Unpin);
249
250impl_str_basic!(OwnedInterfaceName);
251
252impl OwnedInterfaceName {
253 /// Convert to the inner `InterfaceName`, consuming `self`.
254 pub fn into_inner(self) -> InterfaceName<'static> {
255 self.0
256 }
257
258 /// Get a reference to the inner `InterfaceName`.
259 pub fn inner(&self) -> &InterfaceName<'static> {
260 &self.0
261 }
262}
263
264impl Deref for OwnedInterfaceName {
265 type Target = InterfaceName<'static>;
266
267 fn deref(&self) -> &Self::Target {
268 &self.0
269 }
270}
271
272impl Borrow<str> for OwnedInterfaceName {
273 fn borrow(&self) -> &str {
274 self.0.as_str()
275 }
276}
277
278impl From<OwnedInterfaceName> for InterfaceName<'_> {
279 fn from(o: OwnedInterfaceName) -> Self {
280 o.into_inner()
281 }
282}
283
284impl<'unowned, 'owned: 'unowned> From<&'owned OwnedInterfaceName> for InterfaceName<'unowned> {
285 fn from(name: &'owned OwnedInterfaceName) -> Self {
286 InterfaceName::from_str_unchecked(name.as_str())
287 }
288}
289
290impl From<InterfaceName<'_>> for OwnedInterfaceName {
291 fn from(name: InterfaceName<'_>) -> Self {
292 OwnedInterfaceName(name.into_owned())
293 }
294}
295
296impl From<OwnedInterfaceName> for Str<'_> {
297 fn from(value: OwnedInterfaceName) -> Self {
298 value.into_inner().0
299 }
300}
301
302impl<'de> Deserialize<'de> for OwnedInterfaceName {
303 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
304 where
305 D: de::Deserializer<'de>,
306 {
307 String::deserialize(deserializer)
308 .and_then(|n| InterfaceName::try_from(n).map_err(|e| de::Error::custom(e.to_string())))
309 .map(Self)
310 }
311}
312
313impl PartialEq<&str> for OwnedInterfaceName {
314 fn eq(&self, other: &&str) -> bool {
315 self.as_str() == *other
316 }
317}
318
319impl PartialEq<InterfaceName<'_>> for OwnedInterfaceName {
320 fn eq(&self, other: &InterfaceName<'_>) -> bool {
321 self.0 == *other
322 }
323}
324
325impl Debug for OwnedInterfaceName {
326 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
327 f&mut DebugTuple<'_, '_>.debug_tuple(name:"OwnedInterfaceName")
328 .field(&self.as_str())
329 .finish()
330 }
331}
332
333impl Display for OwnedInterfaceName {
334 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
335 Display::fmt(&InterfaceName::from(self), f)
336 }
337}
338
339impl NoneValue for OwnedInterfaceName {
340 type NoneType = <InterfaceName<'static> as NoneValue>::NoneType;
341
342 fn null_value() -> Self::NoneType {
343 InterfaceName::null_value()
344 }
345}
346