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;
}