1use std::path::{Component, Path, PathBuf};
10
11mod default;
12#[cfg(any(unix, target_os = "wasi"))]
13mod unix_wasi;
14#[cfg(windows)]
15mod windows;
16
17#[cfg(not(any(unix, windows, target_os = "wasi")))]
18use default as imp;
19#[cfg(any(unix, target_os = "wasi"))]
20use unix_wasi as imp;
21#[cfg(windows)]
22use windows as imp;
23
24#[must_use]
56pub fn memory_loader_ruby_load_path() -> &'static Path {
57 if cfg!(windows) {
58 Path::new("c:/artichoke/virtual_root/src/lib")
59 } else {
60 Path::new("/artichoke/virtual_root/src/lib")
61 }
62}
63
64#[must_use]
111pub fn is_explicit_relative<P: AsRef<Path>>(path: P) -> bool {
112 let path = path.as_ref();
113 imp::is_explicit_relative(path.as_ref())
114}
115
116#[must_use]
166pub fn is_explicit_relative_bytes<P: AsRef<[u8]>>(path: P) -> bool {
167 let path = path.as_ref();
168 default::is_explicit_relative_bytes(path)
169}
170
171pub fn normalize_slashes(path: PathBuf) -> Result<Vec<u8>, PathBuf> {
183 imp::normalize_slashes(path)
184}
185
186pub fn absolutize_relative_to<T, U>(path: T, cwd: U) -> PathBuf
189where
190 T: AsRef<Path>,
191 U: AsRef<Path>,
192{
193 absolutize_relative_to_inner(path.as_ref(), cwd.as_ref())
194}
195
196fn absolutize_relative_to_inner(path: &Path, cwd: &Path) -> PathBuf {
197 let mut iter = path.components().peekable();
198 let hint = iter.size_hint();
199 let (mut components, cwd_is_relative) = if let Some(Component::RootDir) = iter.peek() {
200 (Vec::with_capacity(hint.1.unwrap_or(hint.0)), false)
201 } else {
202 let mut components = cwd.components().map(Component::as_os_str).collect::<Vec<_>>();
203 components.reserve(hint.1.unwrap_or(hint.0));
204 (components, cwd.is_relative())
205 };
206 for component in iter {
207 match component {
208 Component::CurDir => {}
209 Component::ParentDir if cwd_is_relative => {
210 components.pop();
211 }
212 Component::ParentDir => {
213 components.pop();
214 if components.is_empty() {
215 components.push(Component::RootDir.as_os_str());
216 }
217 }
218 c => {
219 components.push(c.as_os_str());
220 }
221 }
222 }
223 components.into_iter().collect()
224}
225
226#[cfg(test)]
227mod tests {
228 use std::path::Path;
229
230 use super::absolutize_relative_to;
231
232 #[test]
233 fn absolutize_absolute_path() {
234 let path = Path::new("/foo/bar");
235 let cwd = Path::new("/home/artichoke");
236 assert_eq!(absolutize_relative_to(path, cwd), path);
237 let cwd = Path::new("relative/path");
238 assert_eq!(absolutize_relative_to(path, cwd), path);
239 }
240
241 #[test]
242 fn absolutize_absolute_path_dedot_current_dir() {
243 let path = Path::new("/././foo/./bar/./././.");
244 let cwd = Path::new("/home/artichoke");
245 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/foo/bar"));
246 let cwd = Path::new("relative/path");
247 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/foo/bar"));
248 }
249
250 #[test]
251 fn absolutize_absolute_path_dedot_parent_dir() {
252 let path = Path::new("/foo/bar/..");
253 let cwd = Path::new("/home/artichoke");
254 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/foo"));
255 let cwd = Path::new("relative/path");
256 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/foo"));
257
258 let path = Path::new("/foo/../../../../bar/../../../");
259 let cwd = Path::new("/home/artichoke");
260 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/"));
261 let cwd = Path::new("relative/path");
262 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/"));
263
264 let path = Path::new("/foo/../../../../bar/../../../boom/baz");
265 let cwd = Path::new("/home/artichoke");
266 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/boom/baz"));
267 let cwd = Path::new("relative/path");
268 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/boom/baz"));
269 }
270
271 #[test]
272 fn absolutize_relative_path() {
273 let path = Path::new("foo/bar");
274 let cwd = Path::new("/home/artichoke");
275 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/home/artichoke/foo/bar"));
276 let cwd = Path::new("relative/path");
277 assert_eq!(absolutize_relative_to(path, cwd), Path::new("relative/path/foo/bar"));
278 }
279
280 #[test]
281 fn absolutize_relative_path_dedot_current_dir() {
282 let path = Path::new("././././foo/./bar/./././.");
283 let cwd = Path::new("/home/artichoke");
284 assert_eq!(absolutize_relative_to(path, cwd), Path::new("/home/artichoke/foo/bar"));
285 let cwd = Path::new("relative/path");
286 assert_eq!(absolutize_relative_to(path, cwd), Path::new("relative/path/foo/bar"));
287 }
288
289 #[test]
290 #[cfg(unix)]
291 fn absolutize_relative_path_dedot_parent_dir_unix() {
292 let path = Path::new("foo/bar/..");
293 let cwd = Path::new("/home/artichoke");
294 let absolute = absolutize_relative_to(path, cwd);
295 assert_eq!(absolute, Path::new("/home/artichoke/foo"));
296 let cwd = Path::new("relative/path");
297 let absolute = absolutize_relative_to(path, cwd);
298 assert_eq!(absolute, Path::new("relative/path/foo"));
299
300 let path = Path::new("foo/../../../../bar/../../../");
301 let cwd = Path::new("/home/artichoke");
302 let absolute = absolutize_relative_to(path, cwd);
303 assert_eq!(absolute, Path::new("/"));
304 let cwd = Path::new("relative/path");
305 let absolute = absolutize_relative_to(path, cwd);
306 assert_eq!(absolute, Path::new(""));
307
308 let path = Path::new("foo/../../../../bar/../../../boom/baz");
309 let cwd = Path::new("/home/artichoke");
310 let absolute = absolutize_relative_to(path, cwd);
311 assert_eq!(absolute, Path::new("/boom/baz"));
312 let cwd = Path::new("relative/path");
313 let absolute = absolutize_relative_to(path, cwd);
314 assert_eq!(absolute, Path::new("boom/baz"));
315 }
316
317 #[test]
318 #[cfg(windows)]
319 fn absolutize_relative_path_dedot_parent_dir_windows_forward_slash() {
320 let path = Path::new("foo/bar/..");
321 let cwd = Path::new("C:/Users/artichoke");
322 let absolute = absolutize_relative_to(path, cwd);
323 assert_eq!(absolute, Path::new("C:/Users/artichoke/foo"));
324 let cwd = Path::new("relative/path");
325 let absolute = absolutize_relative_to(path, cwd);
326 assert_eq!(absolute, Path::new("relative/path/foo"));
327
328 let path = Path::new("foo/../../../../bar/../../../");
329 let cwd = Path::new("C:/Users/artichoke");
330 let absolute = absolutize_relative_to(path, cwd);
331 assert_eq!(absolute, Path::new("/"));
332 let cwd = Path::new("relative/path");
333 let absolute = absolutize_relative_to(path, cwd);
334 assert_eq!(absolute, Path::new(""));
335
336 let path = Path::new("foo/../../../../bar/../../../boom/baz");
337 let cwd = Path::new("C:/Users/artichoke");
338 let absolute = absolutize_relative_to(path, cwd);
339 assert_eq!(absolute, Path::new("/boom/baz"));
340 let cwd = Path::new("relative/path");
341 let absolute = absolutize_relative_to(path, cwd);
342 assert_eq!(absolute, Path::new("boom/baz"));
343 }
344
345 #[test]
346 #[cfg(windows)]
347 fn absolutize_relative_path_dedot_parent_dir_windows_backward_slash() {
348 let path = Path::new(r"foo\bar\..");
349 let cwd = Path::new(r"C:\Users\artichoke");
350 let absolute = absolutize_relative_to(path, cwd);
351 assert_eq!(absolute, Path::new("C:/Users/artichoke/foo"));
352 let cwd = Path::new(r"relative\path");
353 let absolute = absolutize_relative_to(path, cwd);
354 assert_eq!(absolute, Path::new("relative/path/foo"));
355
356 let path = Path::new(r"foo\..\..\..\..\bar\..\..\..\");
357 let cwd = Path::new(r"C:\Users\artichoke");
358 let absolute = absolutize_relative_to(path, cwd);
359 assert_eq!(absolute, Path::new("/"));
360 let cwd = Path::new(r"relative\path");
361 let absolute = absolutize_relative_to(path, cwd);
362 assert_eq!(absolute, Path::new(""));
363
364 let path = Path::new(r"foo\..\..\..\..\bar\..\..\..\boom\baz");
365 let cwd = Path::new(r"C:\Users\artichoke");
366 let absolute = absolutize_relative_to(path, cwd);
367 assert_eq!(absolute, Path::new("/boom/baz"));
368 let cwd = Path::new(r"relative\path");
369 let absolute = absolutize_relative_to(path, cwd);
370 assert_eq!(absolute, Path::new("boom/baz"));
371 }
372}