1use std::fmt;
2use std::fmt::Formatter;
3
4use itertools::Itertools;
5
6#[derive(Debug, Clone, PartialEq, Hash)]
7pub enum Path {
8 RootlessPath {
9 type_name: &'static str,
10 parts: Vec<String>,
11 },
12 AbemptyPath {
13 type_name: &'static str,
14 parts: Vec<String>,
15 },
16 AbsolutePath {
17 type_name: &'static str,
18 parts: Vec<String>,
19 },
20 NoSchemePath {
21 type_name: &'static str,
22 parts: Vec<String>,
23 },
24 EmptyPath {
25 type_name: &'static str,
26 },
27}
28
29impl Default for Path {
30 fn default() -> Self {
31 Path::of_empty()
32 }
33}
34
35impl fmt::Display for Path {
36 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
37 let root = match self {
38 Path::RootlessPath { .. } | Path::NoSchemePath { .. } | Path::EmptyPath { .. } => "",
39 _ => "/",
40 };
41 write!(f, "{}{}", root, self.parts().join("/"))
42 }
43}
44
45impl Path {
46 pub fn of_rootless_from_strs(parts: &[&str]) -> Self {
47 Path::RootlessPath {
48 type_name: "rootless_path",
49 parts: parts.into_iter().map(|e| e.to_string()).collect_vec(),
50 }
51 }
52
53 pub fn of_rootless_from_strings(parts: &[String]) -> Self {
54 Path::RootlessPath {
55 type_name: "rootless_path",
56 parts: Vec::from(parts),
57 }
58 }
59
60 pub fn of_abempty_from_strs(parts: &[&str]) -> Self {
61 Path::AbemptyPath {
62 type_name: "abempty_path",
63 parts: parts.into_iter().map(|e| e.to_string()).collect_vec(),
64 }
65 }
66
67 pub fn of_abempty_from_strings(parts: &[String]) -> Self {
68 Path::AbemptyPath {
69 type_name: "abempty_path",
70 parts: Vec::from(parts),
71 }
72 }
73
74 pub fn of_absolute_from_strs(parts: &[&str]) -> Self {
75 Path::AbsolutePath {
76 type_name: "absolute_path",
77 parts: parts.into_iter().map(|e| e.to_string()).collect_vec(),
78 }
79 }
80
81 pub fn of_absolute_from_strings(parts: &[String]) -> Self {
82 Path::AbsolutePath {
83 type_name: "absolute_path",
84 parts: Vec::from(parts),
85 }
86 }
87
88 pub fn of_no_scheme_from_strs(parts: &[&str]) -> Self {
89 Path::NoSchemePath {
90 type_name: "no_scheme_path",
91 parts: parts.into_iter().map(|e| e.to_string()).collect_vec(),
92 }
93 }
94
95 pub fn of_no_scheme_from_strings(parts: &[String]) -> Self {
96 Path::NoSchemePath {
97 type_name: "no_scheme_path",
98 parts: Vec::from(parts),
99 }
100 }
101
102 pub fn of_empty() -> Self {
103 Path::EmptyPath {
104 type_name: "empty_path",
105 }
106 }
107
108 pub fn type_name(&self) -> &'static str {
109 match self {
110 &Path::RootlessPath { type_name, .. } => type_name,
111 &Path::AbemptyPath { type_name, .. } => type_name,
112 &Path::AbsolutePath { type_name, .. } => type_name,
113 &Path::NoSchemePath { type_name, .. } => type_name,
114 &Path::EmptyPath { type_name } => type_name,
115 }
116 }
117 pub fn parts(&self) -> &Vec<String> {
118 static EMPTY_PARTS: Vec<String> = vec![];
119 match self {
120 Path::RootlessPath { parts, .. } => parts,
121 Path::AbemptyPath { parts, .. } => parts,
122 Path::AbsolutePath { parts, .. } => parts,
123 Path::NoSchemePath { parts, .. } => parts,
124 Path::EmptyPath { .. } => &EMPTY_PARTS,
125 }
126 }
127
128 pub fn is_empty(&self) -> bool {
129 self.parts().is_empty()
130 }
131
132 pub fn non_empty(&self) -> bool {
133 !self.is_empty()
134 }
135
136 pub fn with_parts(&mut self, parts: Vec<String>) {
137 self.add_parts(parts)
138 }
139
140 pub fn to_rootless(&self) -> Path {
141 Path::of_rootless_from_strings(&self.parts().clone())
142 }
143
144 pub fn to_absolute(&self) -> Path {
145 Path::of_absolute_from_strings(&self.parts().clone())
146 }
147
148 pub fn add_part(&mut self, part: String) {
149 let parts_opt = match self {
150 Path::RootlessPath { parts, .. } => Some(parts),
151 Path::AbemptyPath { parts, .. } => Some(parts),
152 Path::AbsolutePath { parts, .. } => Some(parts),
153 Path::NoSchemePath { parts, .. } => Some(parts),
154 Path::EmptyPath { .. } => None,
155 };
156 match parts_opt {
157 Some(parts) => {
158 parts.push(part);
159 }
160 None => (),
161 }
162 }
163
164 pub fn add_parts(&mut self, parts: Vec<String>) {
165 for x in parts {
166 self.add_part(x)
167 }
168 }
169}