async_rustbus/rustbus_core/
path.rs1use crate::rustbus_core;
28use rustbus_core::signature::{Base, Type};
29use rustbus_core::wire::marshal::traits::{Marshal, Signature, SignatureBuffer};
30use rustbus_core::wire::marshal::MarshalContext;
31use rustbus_core::wire::unmarshal::traits::Unmarshal;
32use rustbus_core::wire::unmarshal::Error as UnmarshalError;
33use rustbus_core::wire::unmarshal::{UnmarshalContext, UnmarshalResult};
34
35use std::borrow::{Borrow, ToOwned};
36use std::cmp::Ordering;
37use std::convert::TryFrom;
38use std::ffi::{OsStr, OsString};
39use std::fmt::{Display, Formatter};
40use std::hash::{Hash, Hasher};
41use std::ops::Deref;
42use std::os::unix::ffi::{OsStrExt, OsStringExt};
43use std::path::{Component, Path, PathBuf, StripPrefixError};
44use std::str::FromStr;
45
46#[derive(Debug)]
48pub enum InvalidObjectPath {
49 NoRoot,
50 ContainsInvalidCharacters,
51 ConsecutiveSlashes,
52 TrailingSlash,
53}
54
55#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
60pub struct ObjectPath {
61 inner: Path,
62}
63impl ObjectPath {
64 fn validate_skip_root(path_str: &str) -> Result<(), InvalidObjectPath> {
65 let mut last_was_sep = false;
66 for character in path_str.chars() {
67 match character {
68 'A'..='Z' | 'a'..='z' | '0'..='9' | '_' => {
69 last_was_sep = false;
70 }
71 '/' => {
72 if last_was_sep {
73 return Err(InvalidObjectPath::ConsecutiveSlashes);
74 } else {
75 last_was_sep = true;
76 }
77 }
78 _ => return Err(InvalidObjectPath::ContainsInvalidCharacters),
79 }
80 }
81 if path_str.len() != 1 && path_str.ends_with('/') {
82 return Err(InvalidObjectPath::TrailingSlash);
83 }
84 Ok(())
85 }
86 fn validate_str(path_str: &str) -> Result<(), InvalidObjectPath> {
87 if !path_str.starts_with('/') {
88 return Err(InvalidObjectPath::NoRoot);
89 }
90 Self::validate_skip_root(path_str)
91 }
92 fn validate<P: AsRef<Path>>(path: P) -> Result<(), InvalidObjectPath> {
93 let path = path.as_ref();
94 if !path.has_root() {
95 return Err(InvalidObjectPath::NoRoot);
96 }
97 let path_str = path
98 .to_str()
99 .ok_or(InvalidObjectPath::ContainsInvalidCharacters)?;
100 Self::validate_skip_root(path_str)
101 }
102 fn debug_assert_validitity(&self) {
103 #[cfg(debug_assertions)]
104 Self::validate(self).expect("Failed to validate the object path!");
105 }
106 #[inline]
118 pub fn from_path<P: AsRef<Path> + ?Sized>(p: &P) -> Result<&ObjectPath, InvalidObjectPath> {
119 let path = p.as_ref();
120 let ret = unsafe {
121 Self::validate(path)?;
122 Self::new_no_val(path)
123 };
124 Ok(ret)
125 }
126 #[inline]
127 #[allow(clippy::should_implement_trait)]
128 pub fn from_str(s: &str) -> Result<&ObjectPath, InvalidObjectPath> {
129 ObjectPath::validate_str(s)?;
130 unsafe { Ok(ObjectPath::new_no_val(s.as_ref())) }
131 }
132 unsafe fn new_no_val(p: &Path) -> &ObjectPath {
133 &*(p as *const Path as *const ObjectPath)
134 }
135 #[inline]
137 pub fn as_bytes(&self) -> &[u8] {
138 self.inner.as_os_str().as_bytes()
139 }
140 #[inline]
144 pub fn as_str(&self) -> &str {
145 self.debug_assert_validitity();
146
147 let bytes = self.as_bytes();
148 unsafe { std::str::from_utf8_unchecked(bytes) }
149 }
150 pub fn strip_prefix<P: AsRef<Path> + ?Sized>(
177 &self,
178 p: &P,
179 ) -> Result<&ObjectPath, StripPrefixError> {
180 let stripped = self.inner.strip_prefix(p.as_ref())?;
181 if stripped == Path::new("") {
182 Ok(unsafe { ObjectPath::new_no_val("/".as_ref()) })
183 } else {
184 let self_bytes = self.as_bytes();
187 let self_len = self_bytes.len(); let stripped_len = stripped.as_os_str().len();
189 let ret_bytes = &self_bytes[self_len - 1 - stripped_len..];
190
191 let ret = OsStr::from_bytes(ret_bytes);
193 let ret = unsafe { ObjectPath::new_no_val(ret.as_ref()) };
194 ret.debug_assert_validitity();
195 Ok(ret)
196 }
197 }
198 pub fn parent(&self) -> Option<&ObjectPath> {
201 let pp = self.inner.parent()?;
202 let ret = unsafe { Self::new_no_val(pp) };
203 ret.debug_assert_validitity();
204 Some(ret)
205 }
206 #[inline]
209 pub fn file_name(&self) -> Option<&str> {
210 self.debug_assert_validitity();
211 let bytes = self.inner.file_name()?.as_bytes();
212 unsafe { Some(std::str::from_utf8_unchecked(bytes)) }
213 }
214 #[inline]
216 pub fn root_path() -> &'static Self {
217 unsafe { ObjectPath::new_no_val("/".as_ref()) }
218 }
219 pub fn components(&self) -> impl Iterator<Item = &str> {
221 self.debug_assert_validitity();
222 self.inner.components().skip(1).map(|c| match c {
223 Component::Normal(os) => unsafe { std::str::from_utf8_unchecked(os.as_bytes()) },
224 _ => unreachable!("All the components of a ObjectPath are normal!"),
225 })
226 }
227 pub fn to_object_path_buf(&self) -> ObjectPathBuf {
228 ObjectPathBuf::from(self)
229 }
230}
231impl Display for ObjectPath {
232 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
233 write!(f, "{}", self.as_str())
234 }
235}
236impl Display for ObjectPathBuf {
237 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
238 self.deref().fmt(f)
239 }
240}
241impl Marshal for &ObjectPath {
242 fn marshal(&self, ctx: &mut MarshalContext) -> Result<(), rustbus_core::Error> {
243 self.as_str().marshal(ctx)
244 }
245}
246impl Marshal for ObjectPathBuf {
247 fn marshal(&self, ctx: &mut MarshalContext) -> Result<(), rustbus_core::Error> {
248 self.deref().marshal(ctx)
249 }
250}
251
252impl Deref for ObjectPath {
253 type Target = std::path::Path;
254
255 #[inline]
256 fn deref(&self) -> &Self::Target {
257 &self.inner
258 }
259}
260impl ToOwned for ObjectPath {
261 type Owned = ObjectPathBuf;
262 #[inline]
263 fn to_owned(&self) -> Self::Owned {
264 self.to_object_path_buf()
265 }
266}
267
268impl Borrow<Path> for ObjectPath {
269 #[inline]
270 fn borrow(&self) -> &Path {
271 self.deref()
272 }
273}
274impl AsRef<Path> for ObjectPath {
275 #[inline]
276 fn as_ref(&self) -> &Path {
277 self.deref()
278 }
279}
280impl AsRef<ObjectPath> for ObjectPath {
281 #[inline]
282 fn as_ref(&self) -> &ObjectPath {
283 self
284 }
285}
286impl AsRef<str> for ObjectPath {
287 #[inline]
288 fn as_ref(&self) -> &str {
289 self.as_str()
290 }
291}
292impl AsRef<OsStr> for ObjectPath {
293 #[inline]
294 fn as_ref(&self) -> &OsStr {
295 self.inner.as_ref()
296 }
297}
298
299impl<'a> From<&'a ObjectPath> for &'a str {
300 #[inline]
301 fn from(path: &'a ObjectPath) -> Self {
302 path.as_str()
303 }
304}
305impl<'a> TryFrom<&'a str> for &'a ObjectPath {
306 type Error = InvalidObjectPath;
307 #[inline]
308 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
309 ObjectPath::from_str(s)
310 }
311}
312impl<'a> TryFrom<&'a Path> for &'a ObjectPath {
313 type Error = InvalidObjectPath;
314 #[inline]
315 fn try_from(p: &'a Path) -> Result<Self, Self::Error> {
316 ObjectPath::from_path(p)
317 }
318}
319
320impl Signature for &ObjectPath {
321 #[inline]
322 fn signature() -> Type {
323 Type::Base(Base::ObjectPath)
324 }
325 #[inline]
326 fn alignment() -> usize {
327 Self::signature().get_alignment()
328 }
329 #[inline]
330 fn sig_str(s_buf: &mut SignatureBuffer) {
331 s_buf.push_static("o");
332 }
333}
334
335impl<'buf, 'fds> Unmarshal<'buf, 'fds> for &'buf ObjectPath {
336 fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> UnmarshalResult<Self> {
337 let (bytes, val) = <&str>::unmarshal(ctx)?;
338 let path = ObjectPath::from_str(val).map_err(|_| UnmarshalError::InvalidType)?;
339 Ok((bytes, path))
340 }
341}
342impl Signature for ObjectPathBuf {
343 #[inline]
344 fn signature() -> Type {
345 <&ObjectPath>::signature()
346 }
347 #[inline]
348 fn alignment() -> usize {
349 <&ObjectPath>::alignment()
350 }
351 #[inline]
352 fn sig_str(s_buf: &mut SignatureBuffer) {
353 <&ObjectPath>::sig_str(s_buf);
354 }
355}
356impl<'buf, 'fds> Unmarshal<'buf, 'fds> for ObjectPathBuf {
357 fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> UnmarshalResult<Self> {
358 <&ObjectPath>::unmarshal(ctx).map(|(size, op)| (size, op.to_owned()))
359 }
360}
361
362#[derive(Eq, Clone, Debug, Default)]
363pub struct ObjectPathBuf {
364 inner: Option<PathBuf>,
365}
366impl Hash for ObjectPathBuf {
367 fn hash<H: Hasher>(&self, state: &mut H) {
368 self.deref().hash(state);
369 }
370}
371impl PartialEq<ObjectPathBuf> for ObjectPathBuf {
372 fn eq(&self, other: &ObjectPathBuf) -> bool {
373 self.deref().eq(other.deref())
374 }
375}
376impl PartialOrd<ObjectPathBuf> for ObjectPathBuf {
377 fn partial_cmp(&self, other: &ObjectPathBuf) -> Option<Ordering> {
378 self.deref().partial_cmp(other)
379 }
380}
381impl Ord for ObjectPathBuf {
382 fn cmp(&self, other: &Self) -> Ordering {
383 self.deref().cmp(other)
384 }
385}
386impl ObjectPathBuf {
403 #[inline]
407 pub fn new() -> ObjectPathBuf {
408 ObjectPathBuf { inner: None }
409 }
410 pub fn with_capacity(capacity: usize) -> ObjectPathBuf {
417 let inner = if capacity == 0 {
418 None
419 } else {
420 let mut pb = PathBuf::with_capacity(capacity);
421 pb.push("/");
422 Some(pb)
423 };
424 ObjectPathBuf { inner }
425 }
426 #[inline]
428 pub fn as_object_path(&self) -> &ObjectPath {
429 self.deref()
430 }
431 unsafe fn from_path_buf(pb: PathBuf) -> Self {
432 Self { inner: Some(pb) }
433 }
434 #[inline]
438 pub fn clear(&mut self) {
439 if let Some(buf) = &mut self.inner {
440 buf.clear();
441 }
442 }
443 #[inline]
444 pub fn push(&mut self, path: &ObjectPath) {
446 let path = Path::strip_prefix(path, "/").expect("All object paths start with '/'");
447 unsafe {
448 self.push_path_unchecked(path);
449 }
450 }
451 unsafe fn push_path_unchecked(&mut self, path: &Path) {
452 let len = path.as_os_str().len();
453 if len == 0 {
454 return;
455 }
456 self.reserve(len + 1);
457 let inner = self
458 .inner
459 .as_mut()
460 .expect("The reserve call cause a PathBuf to allows be allocated.");
461 inner.push(path);
462 self.debug_assert_validitity();
463 }
464 #[inline]
499 pub fn push_path<P: AsRef<Path>>(&mut self, path: P) {
500 self.push_path_checked(path)
501 .expect("Invalid path was passed!");
502 }
503 pub fn push_path_checked<P: AsRef<Path>>(&mut self, path: P) -> Result<(), InvalidObjectPath> {
525 let path = path.as_ref();
526 let path = path.strip_prefix("/").unwrap_or(path);
527 let path_str = path
528 .to_str()
529 .ok_or(InvalidObjectPath::ContainsInvalidCharacters)?;
530 ObjectPath::validate_skip_root(path_str)?;
531 unsafe {
532 self.push_path_unchecked(path);
533 };
534 Ok(())
535 }
536 #[inline]
541 pub fn pop(&mut self) -> bool {
542 self.inner.as_mut().map_or(false, PathBuf::pop)
543 }
544 pub fn reserve(&mut self, additional: usize) {
545 if additional == 0 {
546 return;
547 }
548 match &mut self.inner {
549 Some(buf) => buf.reserve(additional),
550 None => *self = Self::with_capacity(additional + 1),
551 }
552 }
553 pub fn reserve_exact(&mut self, additional: usize) {
554 if additional == 0 {
555 return;
556 }
557 match &mut self.inner {
558 Some(buf) => buf.reserve_exact(additional),
559 None => {
560 let mut buf = PathBuf::new();
561 buf.reserve_exact(additional + 1);
562 self.inner = Some(buf);
563 }
564 }
565 }
566 #[inline]
571 pub fn capacity(&self) -> usize {
572 self.inner.as_ref().map_or(0, PathBuf::capacity)
573 }
574}
575impl TryFrom<OsString> for ObjectPathBuf {
576 type Error = InvalidObjectPath;
577 fn try_from(value: OsString) -> Result<Self, Self::Error> {
578 ObjectPath::validate(&value)?;
579 Ok(unsafe { ObjectPathBuf::from_path_buf(value.into()) })
580 }
581}
582impl TryFrom<String> for ObjectPathBuf {
583 type Error = InvalidObjectPath;
584 #[inline]
585 fn try_from(value: String) -> Result<Self, Self::Error> {
586 Self::try_from(OsString::from(value))
587 }
588}
589impl TryFrom<PathBuf> for ObjectPathBuf {
590 type Error = InvalidObjectPath;
591 #[inline]
592 fn try_from(value: PathBuf) -> Result<Self, Self::Error> {
593 ObjectPath::validate(&value)?;
594 Ok(unsafe { ObjectPathBuf::from_path_buf(value) })
595 }
596}
597impl TryFrom<&str> for ObjectPathBuf {
598 type Error = InvalidObjectPath;
599 #[inline]
600 fn try_from(value: &str) -> Result<Self, Self::Error> {
601 ObjectPathBuf::from_str(value)
602 }
603}
604impl TryFrom<&OsStr> for ObjectPathBuf {
605 type Error = InvalidObjectPath;
606 #[inline]
607 fn try_from(value: &OsStr) -> Result<Self, Self::Error> {
608 ObjectPath::from_path(value).map(ToOwned::to_owned)
609 }
610}
611impl TryFrom<&Path> for ObjectPathBuf {
612 type Error = InvalidObjectPath;
613 #[inline]
614 fn try_from(value: &Path) -> Result<Self, Self::Error> {
615 ObjectPath::from_path(value).map(ToOwned::to_owned)
616 }
617}
618
619impl Deref for ObjectPathBuf {
620 type Target = ObjectPath;
621 fn deref(&self) -> &Self::Target {
622 match &self.inner {
623 Some(buf) => unsafe { ObjectPath::new_no_val(buf) },
624 None => ObjectPath::root_path(),
625 }
626 }
627}
628impl Borrow<ObjectPath> for ObjectPathBuf {
629 #[inline]
630 fn borrow(&self) -> &ObjectPath {
631 self.deref()
632 }
633}
634impl AsRef<ObjectPath> for ObjectPathBuf {
635 #[inline]
636 fn as_ref(&self) -> &ObjectPath {
637 self.deref()
638 }
639}
640impl AsRef<str> for ObjectPathBuf {
641 #[inline]
642 fn as_ref(&self) -> &str {
643 self.deref().as_ref()
644 }
645}
646impl AsRef<Path> for ObjectPathBuf {
647 #[inline]
648 fn as_ref(&self) -> &Path {
649 self.deref().as_ref()
650 }
651}
652impl FromStr for ObjectPathBuf {
653 type Err = InvalidObjectPath;
654 #[inline]
655 fn from_str(s: &str) -> Result<Self, Self::Err> {
656 ObjectPath::from_str(s).map(ToOwned::to_owned)
657 }
658}
659impl From<ObjectPathBuf> for PathBuf {
660 #[inline]
661 fn from(buf: ObjectPathBuf) -> Self {
662 match buf.inner {
663 Some(buf) => buf,
664 None => PathBuf::from("/"),
665 }
666 }
667}
668impl From<ObjectPathBuf> for String {
669 fn from(path: ObjectPathBuf) -> Self {
670 path.debug_assert_validitity();
671 let bytes = match path.inner {
672 Some(buf) => buf.into_os_string().into_vec(),
673 None => Vec::from(&b"/"[..]),
674 };
675
676 unsafe { std::string::String::from_utf8_unchecked(bytes) }
677 }
678}
679impl From<&ObjectPath> for ObjectPathBuf {
680 fn from(path: &ObjectPath) -> Self {
681 let ret = if path == ObjectPath::root_path() {
682 ObjectPathBuf::new()
683 } else {
684 unsafe { ObjectPathBuf::from_path_buf(path.into()) }
685 };
686 ret.debug_assert_validitity();
687 ret
688 }
689}
690
691impl PartialEq<ObjectPath> for ObjectPathBuf {
692 #[inline]
693 fn eq(&self, other: &ObjectPath) -> bool {
694 self.deref().eq(other)
695 }
696}
697#[cfg(test)]
698mod tests {
699 use super::{ObjectPath, ObjectPathBuf};
700 use std::borrow::Borrow;
701 use std::collections::hash_map::DefaultHasher;
702 use std::hash::{Hash, Hasher};
703 use std::path::Path;
704
705 fn test_objpaths() -> Vec<&'static ObjectPath> {
706 vec![
707 ObjectPath::from_str("/org/freedesktop/NetworkManager").unwrap(),
708 ObjectPath::from_str("/org/freedesktop/NetworkManager/ActiveConnection").unwrap(),
709 ]
710 }
711 fn test_objpathbufs() -> Vec<ObjectPathBuf> {
712 test_objpaths()
713 .into_iter()
714 .map(|op| op.to_owned())
715 .collect()
716 }
717 fn compare_ord_borrow<A, T, U>(pre: &[A]) -> Option<(usize, usize)>
719 where
720 T: Ord + Borrow<U> + ?Sized,
721 U: Ord + ?Sized,
722 A: Borrow<T>,
723 {
724 let pre_iter = pre.iter().map(|p| p.borrow());
725 for (i, pre_i) in pre_iter.clone().enumerate() {
726 for (j, pre_j) in pre_iter.clone().enumerate().skip(i) {
727 let pre_ord = pre_i.cmp(pre_j);
728 let post_i = pre_i.borrow();
729 let post_j = pre_j.borrow();
730 let post_ord = post_i.cmp(post_j);
731 if pre_ord != post_ord {
732 return Some((i, j));
733 }
734 }
735 }
736 None
737 }
738 fn compare_hasher_borrow<A, T, U>(pre: &[A]) -> Option<usize>
741 where
742 T: Hash + Borrow<U> + ?Sized,
743 U: Hash + ?Sized,
744 A: Borrow<T>,
745 {
746 let pre_iter = pre.iter().map(|p| p.borrow());
747 for (i, (pre, post)) in pre_iter
748 .clone()
749 .zip(pre_iter.map(|p| p.borrow()))
750 .enumerate()
751 {
752 let mut pre_borrow_hasher = DefaultHasher::new();
753 let mut post_borrow_hasher = DefaultHasher::new();
754 pre.hash(&mut pre_borrow_hasher);
755 post.hash(&mut post_borrow_hasher);
756 if pre_borrow_hasher.finish() != post_borrow_hasher.finish() {
757 return Some(i);
758 }
759 }
760 None
761 }
762 #[test]
763 fn test_objectpathbuf_borrow_objectpath() {
764 let objpathbufs = test_objpathbufs();
765 if let Some(i) =
766 compare_hasher_borrow::<ObjectPathBuf, ObjectPathBuf, ObjectPath>(&objpathbufs[..])
767 {
768 panic!("Hash didn't match: {}", i);
769 }
770 if let Some((i, j)) =
771 compare_ord_borrow::<ObjectPathBuf, ObjectPathBuf, ObjectPath>(&objpathbufs[..])
772 {
773 panic!("Ord didn't match for: {} {}", i, j);
774 }
775 }
776 #[test]
777 fn test_objectpath_borrow_path() {
778 let objpaths = test_objpaths();
779 if let Some(i) = compare_hasher_borrow::<&ObjectPath, ObjectPath, Path>(&objpaths[..]) {
780 panic!("Hash didn't match: {}", i);
781 }
782 if let Some((i, j)) = compare_ord_borrow::<&ObjectPath, ObjectPath, Path>(&objpaths[..]) {
783 panic!("Ord didn't match for: {} {}", i, j);
784 }
785 }
786 #[test]
787 fn test_push() {
788 let objpath = ObjectPath::from_str("/dbus/test").unwrap();
789 let objpath2 = ObjectPath::from_str("/freedesktop/more").unwrap();
790 let mut objpathbuf = ObjectPathBuf::new();
791 objpathbuf.push(objpath);
792 assert_eq!(objpathbuf, *objpath);
793 objpathbuf.push(objpath2);
794 assert_eq!(
795 &objpathbuf,
796 ObjectPath::from_str("/dbus/test/freedesktop/more").unwrap()
797 );
798 assert!(objpathbuf.starts_with(objpath));
799 assert!(!objpathbuf.starts_with(objpath2));
800 assert_eq!(objpathbuf.strip_prefix(objpath).unwrap(), objpath2);
801 }
802}