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