zvariant/
object_path.rs
1use core::{fmt::Debug, str};
2use serde::{
3 de::{self, Deserialize, Deserializer, Visitor},
4 ser::{Serialize, Serializer},
5};
6use static_assertions::assert_impl_all;
7use std::borrow::Cow;
8
9use crate::{serialized::Format, Basic, Error, Result, Signature, Str, Type};
10
11#[derive(PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
36pub struct ObjectPath<'a>(Str<'a>);
37
38assert_impl_all!(ObjectPath<'_>: Send, Sync, Unpin);
39
40impl<'a> ObjectPath<'a> {
41 pub fn as_ref(&self) -> ObjectPath<'_> {
43 ObjectPath(self.0.as_ref())
44 }
45
46 pub fn as_str(&self) -> &str {
48 self.0.as_str()
49 }
50
51 pub fn as_bytes(&self) -> &[u8] {
53 self.0.as_bytes()
54 }
55
56 pub unsafe fn from_bytes_unchecked<'s: 'a>(bytes: &'s [u8]) -> Self {
65 Self(std::str::from_utf8_unchecked(bytes).into())
66 }
67
68 pub fn from_str_unchecked<'s: 'a>(path: &'s str) -> Self {
73 Self(path.into())
74 }
75
76 pub fn from_static_str(name: &'static str) -> Result<Self> {
78 ensure_correct_object_path_str(name.as_bytes())?;
79
80 Ok(Self::from_static_str_unchecked(name))
81 }
82
83 pub const fn from_static_str_unchecked(name: &'static str) -> Self {
85 Self(Str::from_static(name))
86 }
87
88 pub fn from_string_unchecked(path: String) -> Self {
93 Self(path.into())
94 }
95
96 pub fn len(&self) -> usize {
98 self.0.len()
99 }
100
101 pub fn is_empty(&self) -> bool {
103 self.0.is_empty()
104 }
105
106 pub fn to_owned(&self) -> ObjectPath<'static> {
108 ObjectPath(self.0.to_owned())
109 }
110
111 pub fn into_owned(self) -> ObjectPath<'static> {
113 ObjectPath(self.0.into_owned())
114 }
115}
116
117impl std::default::Default for ObjectPath<'_> {
118 fn default() -> Self {
119 ObjectPath::from_static_str_unchecked("/")
120 }
121}
122
123impl<'a> Basic for ObjectPath<'a> {
124 const SIGNATURE_CHAR: char = 'o';
125 const SIGNATURE_STR: &'static str = "o";
126
127 fn alignment(format: Format) -> usize {
128 match format {
129 Format::DBus => <&str>::alignment(format),
130 #[cfg(feature = "gvariant")]
131 Format::GVariant => 1,
132 }
133 }
134}
135
136impl<'a> Type for ObjectPath<'a> {
137 fn signature() -> Signature<'static> {
138 Signature::from_static_str_unchecked(Self::SIGNATURE_STR)
139 }
140}
141
142impl<'a> TryFrom<&'a [u8]> for ObjectPath<'a> {
143 type Error = Error;
144
145 fn try_from(value: &'a [u8]) -> Result<Self> {
146 ensure_correct_object_path_str(value)?;
147
148 unsafe { Ok(Self::from_bytes_unchecked(value)) }
150 }
151}
152
153impl<'a> TryFrom<&'a str> for ObjectPath<'a> {
155 type Error = Error;
156
157 fn try_from(value: &'a str) -> Result<Self> {
158 Self::try_from(value.as_bytes())
159 }
160}
161
162impl<'a> TryFrom<String> for ObjectPath<'a> {
163 type Error = Error;
164
165 fn try_from(value: String) -> Result<Self> {
166 ensure_correct_object_path_str(value.as_bytes())?;
167
168 Ok(Self::from_string_unchecked(value))
169 }
170}
171
172impl<'a> TryFrom<Cow<'a, str>> for ObjectPath<'a> {
173 type Error = Error;
174
175 fn try_from(value: Cow<'a, str>) -> Result<Self> {
176 match value {
177 Cow::Borrowed(s) => Self::try_from(s),
178 Cow::Owned(s) => Self::try_from(s),
179 }
180 }
181}
182
183impl<'o> From<&ObjectPath<'o>> for ObjectPath<'o> {
184 fn from(o: &ObjectPath<'o>) -> Self {
185 o.clone()
186 }
187}
188
189impl<'a> std::ops::Deref for ObjectPath<'a> {
190 type Target = str;
191
192 fn deref(&self) -> &Self::Target {
193 self.as_str()
194 }
195}
196
197impl<'a> PartialEq<str> for ObjectPath<'a> {
198 fn eq(&self, other: &str) -> bool {
199 self.as_str() == other
200 }
201}
202
203impl<'a> PartialEq<&str> for ObjectPath<'a> {
204 fn eq(&self, other: &&str) -> bool {
205 self.as_str() == *other
206 }
207}
208
209impl<'a> Debug for ObjectPath<'a> {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 f.debug_tuple("ObjectPath").field(&self.as_str()).finish()
212 }
213}
214
215impl<'a> std::fmt::Display for ObjectPath<'a> {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 std::fmt::Display::fmt(&self.as_str(), f)
218 }
219}
220
221impl<'a> Serialize for ObjectPath<'a> {
222 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
223 where
224 S: Serializer,
225 {
226 serializer.serialize_str(self.as_str())
227 }
228}
229
230impl<'de: 'a, 'a> Deserialize<'de> for ObjectPath<'a> {
231 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
232 where
233 D: Deserializer<'de>,
234 {
235 let visitor = ObjectPathVisitor;
236
237 deserializer.deserialize_str(visitor)
238 }
239}
240
241struct ObjectPathVisitor;
242
243impl<'de> Visitor<'de> for ObjectPathVisitor {
244 type Value = ObjectPath<'de>;
245
246 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
247 formatter.write_str("an ObjectPath")
248 }
249
250 #[inline]
251 fn visit_borrowed_str<E>(self, value: &'de str) -> core::result::Result<ObjectPath<'de>, E>
252 where
253 E: serde::de::Error,
254 {
255 ObjectPath::try_from(value).map_err(serde::de::Error::custom)
256 }
257}
258
259fn ensure_correct_object_path_str(path: &[u8]) -> Result<()> {
260 let mut prev = b'\0';
261
262 if path.is_empty() {
270 return Err(serde::de::Error::invalid_length(0, &"> 0 character"));
271 }
272
273 for i in 0..path.len() {
274 let c = path[i];
275
276 if i == 0 && c != b'/' {
277 return Err(serde::de::Error::invalid_value(
278 serde::de::Unexpected::Char(c as char),
279 &"/",
280 ));
281 } else if c == b'/' && prev == b'/' {
282 return Err(serde::de::Error::invalid_value(
283 serde::de::Unexpected::Str("//"),
284 &"/",
285 ));
286 } else if path.len() > 1 && i == (path.len() - 1) && c == b'/' {
287 return Err(serde::de::Error::invalid_value(
288 serde::de::Unexpected::Char('/'),
289 &"an alphanumeric character or `_`",
290 ));
291 } else if !c.is_ascii_alphanumeric() && c != b'/' && c != b'_' {
292 return Err(serde::de::Error::invalid_value(
293 serde::de::Unexpected::Char(c as char),
294 &"an alphanumeric character, `_` or `/`",
295 ));
296 }
297 prev = c;
298 }
299
300 Ok(())
301}
302
303#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize, Type)]
305pub struct OwnedObjectPath(ObjectPath<'static>);
306
307assert_impl_all!(OwnedObjectPath: Send, Sync, Unpin);
308
309impl OwnedObjectPath {
310 pub fn into_inner(self) -> ObjectPath<'static> {
311 self.0
312 }
313}
314
315impl Basic for OwnedObjectPath {
316 const SIGNATURE_CHAR: char = ObjectPath::SIGNATURE_CHAR;
317 const SIGNATURE_STR: &'static str = ObjectPath::SIGNATURE_STR;
318
319 fn alignment(format: Format) -> usize {
320 ObjectPath::alignment(format)
321 }
322}
323
324impl std::ops::Deref for OwnedObjectPath {
325 type Target = ObjectPath<'static>;
326
327 fn deref(&self) -> &Self::Target {
328 &self.0
329 }
330}
331
332impl std::convert::From<OwnedObjectPath> for ObjectPath<'static> {
333 fn from(o: OwnedObjectPath) -> Self {
334 o.into_inner()
335 }
336}
337
338impl std::convert::From<OwnedObjectPath> for crate::Value<'_> {
339 fn from(o: OwnedObjectPath) -> Self {
340 o.into_inner().into()
341 }
342}
343
344impl<'unowned, 'owned: 'unowned> From<&'owned OwnedObjectPath> for ObjectPath<'unowned> {
345 fn from(o: &'owned OwnedObjectPath) -> Self {
346 ObjectPath::from_str_unchecked(o.as_str())
347 }
348}
349
350impl<'a> std::convert::From<ObjectPath<'a>> for OwnedObjectPath {
351 fn from(o: ObjectPath<'a>) -> Self {
352 OwnedObjectPath(o.into_owned())
353 }
354}
355
356impl TryFrom<&'_ str> for OwnedObjectPath {
357 type Error = Error;
358
359 fn try_from(value: &str) -> Result<Self> {
360 Ok(Self::from(ObjectPath::try_from(value)?))
361 }
362}
363
364impl TryFrom<String> for OwnedObjectPath {
365 type Error = Error;
366
367 fn try_from(value: String) -> Result<Self> {
368 Ok(Self::from(ObjectPath::try_from(value)?))
369 }
370}
371
372impl<'de> Deserialize<'de> for OwnedObjectPath {
373 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
374 where
375 D: Deserializer<'de>,
376 {
377 String::deserialize(deserializer)
378 .and_then(|s| ObjectPath::try_from(s).map_err(|e| de::Error::custom(e.to_string())))
379 .map(Self)
380 }
381}
382
383impl std::fmt::Display for OwnedObjectPath {
384 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
385 std::fmt::Display::fmt(&self.as_str(), f)
386 }
387}
388
389#[cfg(test)]
390mod unit {
391 use super::*;
392
393 #[test]
394 fn owned_from_reader() {
395 let json_str = "\"/some/path\"";
397 serde_json::de::from_reader::<_, OwnedObjectPath>(json_str.as_bytes()).unwrap();
398 }
399}