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