1use std::{
2 ffi::OsStr,
3 fmt,
4 ops::{Deref, DerefMut},
5 path::{Path, PathBuf, MAIN_SEPARATOR},
6};
7
8pub struct FastPathBuf {
13 inner: Vec<u8>,
14 last_len: usize,
15}
16
17impl FastPathBuf {
18 #[must_use]
19 pub fn new() -> Self {
20 Self::with_capacity(0)
21 }
22
23 #[must_use]
24 pub fn with_capacity(capacity: usize) -> Self {
25 Self {
26 inner: Vec::with_capacity(capacity),
27 last_len: 0,
28 }
29 }
30
31 pub fn capacity(&self) -> usize {
32 self.inner.capacity()
33 }
34
35 pub fn reserve(&mut self, additional: usize) {
36 self.inner.reserve(additional);
37 }
38
39 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace"))]
40 pub fn push(&mut self, name: &str) -> PopGuard {
41 PopGuard::push(self, name)
42 }
43
44 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace"))]
45 pub unsafe fn pop(&mut self) {
46 let Self {
47 ref mut inner,
48 last_len,
49 } = *self;
50
51 if inner.len() > last_len {
52 inner.truncate(last_len);
53 } else {
54 self.inner.truncate({
55 let parent = self.parent();
56 let parent = unsafe { parent.unwrap_unchecked() };
57 parent.as_os_str().len()
58 });
59 }
60 }
61
62 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace"))]
63 pub unsafe fn set_file_name(&mut self, name: &str) {
64 unsafe {
65 self.pop();
66 }
67 self.push(name);
68 }
69
70 #[cfg(all(unix, not(miri)))]
71 pub fn to_cstr_mut(&mut self) -> unix::CStrFastPathBufGuard {
72 unix::CStrFastPathBufGuard::new(self)
73 }
74}
75
76impl From<PathBuf> for FastPathBuf {
77 fn from(p: PathBuf) -> Self {
78 let inner = p.into_os_string().into_encoded_bytes();
79 Self {
80 last_len: inner.len(),
81 inner,
82 }
83 }
84}
85
86impl Default for FastPathBuf {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92impl Deref for FastPathBuf {
93 type Target = Path;
94
95 fn deref(&self) -> &Self::Target {
96 let Self {
97 ref inner,
98 last_len: _,
99 } = *self;
100
101 unsafe { OsStr::from_encoded_bytes_unchecked(inner) }.as_ref()
102 }
103}
104
105impl AsRef<Path> for FastPathBuf {
106 fn as_ref(&self) -> &Path {
107 self
108 }
109}
110
111impl fmt::Debug for FastPathBuf {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 fmt::Debug::fmt(&**self, f)
114 }
115}
116
117impl Clone for FastPathBuf {
118 fn clone(&self) -> Self {
119 let Self {
120 ref inner,
121 last_len,
122 } = *self;
123
124 Self {
125 inner: inner.clone(),
126 last_len,
127 }
128 }
129
130 fn clone_from(&mut self, source: &Self) {
131 let Self {
132 ref mut inner,
133 ref mut last_len,
134 } = *self;
135
136 inner.clone_from(&source.inner);
137 *last_len = source.last_len;
138 }
139}
140
141pub struct PopGuard<'a>(&'a mut FastPathBuf);
142
143impl<'a> PopGuard<'a> {
144 fn push(path: &'a mut FastPathBuf, name: &str) -> Self {
145 let FastPathBuf {
146 ref mut inner,
147 ref mut last_len,
148 } = *path;
149
150 *last_len = inner.len();
151
152 inner.reserve(1 + name.len() + 1);
154 inner.push(MAIN_SEPARATOR as u8);
155 inner.extend_from_slice(name.as_bytes());
156
157 Self(path)
158 }
159
160 pub fn pop(self) {
161 unsafe { self.0.pop() }
162 }
163}
164
165impl Deref for PopGuard<'_> {
166 type Target = FastPathBuf;
167
168 fn deref(&self) -> &Self::Target {
169 self.0
170 }
171}
172
173impl DerefMut for PopGuard<'_> {
174 fn deref_mut(&mut self) -> &mut Self::Target {
175 self.0
176 }
177}
178
179impl AsRef<Path> for PopGuard<'_> {
180 fn as_ref(&self) -> &Path {
181 self.0
182 }
183}
184
185impl fmt::Debug for PopGuard<'_> {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 fmt::Debug::fmt(&**self, f)
188 }
189}
190
191#[cfg(all(unix, not(miri)))]
192mod unix {
193 use std::{ffi::CStr, ops::Deref};
194
195 use super::FastPathBuf;
196
197 #[must_use]
198 pub struct CStrFastPathBufGuard<'a> {
199 buf: &'a mut FastPathBuf,
200 }
201
202 impl<'a> CStrFastPathBufGuard<'a> {
203 pub fn new(buf: &mut FastPathBuf) -> CStrFastPathBufGuard {
204 let FastPathBuf {
205 ref mut inner,
206 last_len: _,
207 } = *buf;
208
209 inner.push(0); CStrFastPathBufGuard { buf }
211 }
212 }
213
214 impl<'a> Deref for CStrFastPathBufGuard<'a> {
215 type Target = CStr;
216
217 fn deref(&self) -> &Self::Target {
218 let Self {
219 buf:
220 FastPathBuf {
221 ref inner,
222 last_len: _,
223 },
224 } = *self;
225
226 if cfg!(debug_assertions) {
227 CStr::from_bytes_with_nul(inner).unwrap()
228 } else {
229 unsafe { CStr::from_bytes_with_nul_unchecked(inner) }
230 }
231 }
232 }
233
234 impl<'a> AsRef<CStr> for CStrFastPathBufGuard<'a> {
235 fn as_ref(&self) -> &CStr {
236 self
237 }
238 }
239
240 impl<'a> Drop for CStrFastPathBufGuard<'a> {
241 fn drop(&mut self) {
242 let Self {
243 buf:
244 FastPathBuf {
245 ref mut inner,
246 last_len: _,
247 },
248 } = *self;
249
250 inner.pop();
251 }
252 }
253}