1use std::{
2 borrow::Cow,
3 ffi::{OsStr, OsString},
4 io,
5 path::{Component, Path, PathBuf, MAIN_SEPARATOR_STR},
6};
7
8use crate::ParseDot;
9
10impl ParseDot for Path {
11 #[inline]
12 fn parse_dot(&self) -> io::Result<Cow<'_, Path>> {
13 match self.components().next() {
14 Some(Component::CurDir | Component::ParentDir) => {
15 let cwd = get_cwd!();
16
17 self.parse_dot_from(cwd)
18 },
19 _ => self.parse_dot_from(Path::new("")),
21 }
22 }
23
24 fn parse_dot_from(&self, cwd: impl AsRef<Path>) -> io::Result<Cow<'_, Path>> {
25 let main_separator = OsStr::new(MAIN_SEPARATOR_STR);
26
27 let mut iter = self.components();
28
29 let mut has_dots = false;
30
31 if let Some(first_component) = iter.next() {
32 let mut tokens = Vec::new();
33
34 let first_is_root = match first_component {
35 Component::RootDir => {
36 tokens.push(main_separator);
37
38 true
39 },
40 Component::CurDir => {
41 has_dots = true;
42
43 let cwd = cwd.as_ref();
44
45 for token in cwd.iter() {
46 tokens.push(token);
47 }
48
49 !tokens.is_empty() && tokens[0] == main_separator
50 },
51 Component::ParentDir => {
52 has_dots = true;
53
54 let cwd = cwd.as_ref();
55
56 match cwd.parent() {
57 Some(cwd_parent) => {
58 for token in cwd_parent.iter() {
59 tokens.push(token);
60 }
61
62 !tokens.is_empty() && tokens[0] == main_separator
63 },
64 None => {
65 if cwd == main_separator {
67 tokens.push(main_separator);
68
69 true
70 } else {
71 false
72 }
73 },
74 }
75 },
76 _ => {
77 tokens.push(first_component.as_os_str());
78
79 false
80 },
81 };
82
83 for component in iter {
84 match component {
85 Component::CurDir => {
86 has_dots = true;
88 },
89 Component::ParentDir => {
90 let tokens_length = tokens.len();
91
92 if tokens_length > 0 && (tokens_length != 1 || !first_is_root) {
93 tokens.pop();
94 }
95
96 has_dots = true;
97 },
98 _ => {
99 tokens.push(component.as_os_str());
100 },
101 }
102 }
103
104 if tokens.is_empty() {
106 return Ok(Cow::from(PathBuf::new()));
107 }
108
109 let tokens_length = tokens.len();
110
111 let mut size = tokens.iter().fold(tokens_length - 1, |acc, &x| acc + x.len());
112
113 if first_is_root && tokens_length > 1 {
114 size -= 1;
115 }
116
117 if has_dots || size != self.as_os_str().len() {
118 let mut path_string = OsString::with_capacity(size);
119
120 let mut iter = tokens.iter();
121
122 path_string.push(iter.next().unwrap());
123
124 if tokens_length > 1 {
125 if !first_is_root {
126 path_string.push(main_separator);
127 }
128
129 for token in iter.take(tokens_length - 2) {
130 path_string.push(token);
131
132 path_string.push(main_separator);
133 }
134
135 path_string.push(tokens[tokens_length - 1]);
136 }
137
138 let path_buf = PathBuf::from(path_string);
139
140 Ok(Cow::from(path_buf))
141 } else {
142 Ok(Cow::from(self))
143 }
144 } else {
145 Ok(Cow::from(self))
146 }
147 }
148}