1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
// SPDX-FileCopyrightText: The im-pathtree authors
// SPDX-License-Identifier: MPL-2.0
use std::{
borrow::Cow,
ffi::{OsStr, OsString},
fmt,
hash::Hash,
};
/// Owned path segment.
pub trait PathSegment: Clone + Eq + Hash + fmt::Debug {
fn empty() -> Self;
/// Check if the segment is empty.
#[must_use]
fn is_empty(&self) -> bool;
}
/// Borrowed path segment.
pub trait PathSegmentRef<T: PathSegment>: Eq + Hash + fmt::Debug {
/// Check if the segment is empty.
#[must_use]
fn is_empty(&self) -> bool;
/// Check if the segment is equal to the given value.
// TODO: How to avoid this unhandy equality comparison method?
#[must_use]
fn equals(&self, other: &T) -> bool;
/// Convert the borrowed segment reference to an owned value.
// TODO: How to use ToOwned for this purpose? The conflicting implementation
// for Cow<'a, str> currently prevents this.
#[must_use]
fn to_owned(&self) -> T;
}
impl PathSegment for String {
fn empty() -> Self {
Self::new()
}
fn is_empty(&self) -> bool {
self.as_str().is_empty()
}
}
impl PathSegmentRef<String> for str {
fn is_empty(&self) -> bool {
self.is_empty()
}
fn equals(&self, other: &String) -> bool {
self == other
}
fn to_owned(&self) -> String {
String::from(self)
}
}
impl<'a> PathSegment for Cow<'a, str> {
fn empty() -> Self {
Cow::Borrowed("")
}
fn is_empty(&self) -> bool {
self.as_ref().is_empty()
}
}
impl<'a> PathSegmentRef<Cow<'a, str>> for str {
fn is_empty(&self) -> bool {
self.is_empty()
}
fn equals(&self, other: &Cow<'a, str>) -> bool {
self == other
}
fn to_owned(&self) -> Cow<'a, str> {
Cow::Owned(String::from(self))
}
}
impl PathSegment for OsString {
fn empty() -> Self {
Self::new()
}
fn is_empty(&self) -> bool {
self.as_os_str().is_empty()
}
}
impl PathSegmentRef<OsString> for OsStr {
fn is_empty(&self) -> bool {
self.is_empty()
}
fn equals(&self, other: &OsString) -> bool {
self == other
}
fn to_owned(&self) -> OsString {
self.to_os_string()
}
}
/// Decomposition of a path into segments.
pub trait SegmentedPath<S: PathSegment, R: PathSegmentRef<S> + ?Sized>:
Clone + Eq + Hash + fmt::Debug
{
/// Iterate over all path segments.
///
/// All segments are guaranteed to be non-empty.
// TODO: How to avoid boxing the result?
#[must_use]
fn segments(&self) -> Box<dyn Iterator<Item = &R> + '_>;
/// Split the path into parent segments and the last child segment.
///
/// The returned iterator excludes the last segment that is
/// included by [`Self::segments()`].
// TODO: How to avoid boxing the result?
#[must_use]
fn parent_child_segments(&self) -> (Box<dyn Iterator<Item = &R> + '_>, Option<&R>);
}
/// Absolute path with a root.
pub trait RootPath<S: PathSegment, R: PathSegmentRef<S> + ?Sized>: SegmentedPath<S, R> {
/// The root path.
#[must_use]
fn root() -> Self;
/// Check if the path equals the root path.
#[must_use]
fn is_root(&self) -> bool;
}