sweet_utils/path_utils/
path_ext.rs

1use super::FsError;
2use super::FsExt;
3use super::FsResult;
4use std::ffi::OsStr;
5use std::path::Path;
6use std::path::PathBuf;
7
8pub struct PathExt;
9
10impl PathExt {
11	/// Create a path relative to the current working directory
12	/// ## Errors
13	/// If the current working directory cannot be determined
14	pub fn relative(path: &impl AsRef<Path>) -> FsResult<&Path> {
15		let cwd = FsExt::current_dir()?;
16		PathExt::strip_prefix(path, &cwd)
17	}
18
19	/// Strip prefix
20	pub fn strip_prefix<'a>(
21		path: &'a impl AsRef<Path>,
22		prefix: &impl AsRef<Path>,
23	) -> FsResult<&'a Path> {
24		path.as_ref()
25			.strip_prefix(prefix)
26			.map_err(|e| FsError::other(path.as_ref(), e))
27	}
28
29	/// Wraps [`Path::canonicalize`] error with a [`FsError`], actually
30	/// outputting the path that caused the error.
31	pub fn canonicalize(path: impl AsRef<Path>) -> FsResult<PathBuf> {
32		path.as_ref()
33			.canonicalize()
34			.map_err(|e| FsError::io(path, e))
35	}
36
37	/// Create a relative path from a source to a destination:
38	/// ## Example
39	/// ```rust
40	///	# use sweet_utils::prelude::*;
41	/// # use std::path::PathBuf;
42	/// assert_eq!(
43	///		PathExt::create_relative("src", "src/lib.rs").unwrap(),
44	///		PathBuf::from("lib.rs")
45	/// );
46	/// assert_eq!(
47	///		PathExt::create_relative("foo/src", "foo/Cargo.toml").unwrap(),
48	///		PathBuf::from("../Cargo.toml")
49	///	);
50	/// ```
51	pub fn create_relative(
52		src: impl AsRef<Path>,
53		dst: impl AsRef<Path>,
54	) -> FsResult<PathBuf> {
55		let path = src.as_ref();
56		let dst = dst.as_ref();
57		pathdiff::diff_paths(dst, path).ok_or_else(|| {
58			FsError::other(
59				path,
60				format!("Could not create relative path to dest: {:?}", dst),
61			)
62		})
63	}
64
65	pub fn to_forward_slash(path: impl AsRef<Path>) -> PathBuf {
66		path.as_ref().to_string_lossy().replace("\\", "/").into()
67	}
68
69	pub fn file_stem(path: &impl AsRef<Path>) -> FsResult<&OsStr> {
70		let path = path.as_ref();
71		path.file_stem()
72			.ok_or_else(|| FsError::other(path, "No file stem"))
73	}
74	pub fn file_name(path: &impl AsRef<Path>) -> FsResult<&OsStr> {
75		let path = path.as_ref();
76		path.file_name()
77			.ok_or_else(|| FsError::other(path, "No file name"))
78	}
79	pub fn is_dir_or_extension(path: &impl AsRef<Path>, ext: &str) -> bool {
80		let path = path.as_ref();
81		match path.extension() {
82			Some(value) => value.to_str().unwrap() == ext,
83			None => path.is_dir(),
84		}
85	}
86}
87
88
89#[cfg(test)]
90mod test {
91	use crate::prelude::*;
92	use std::path::PathBuf;
93
94	#[test]
95	fn works() {
96		assert_eq!(
97			PathExt::create_relative("src", "src/lib.rs").unwrap(),
98			PathBuf::from("lib.rs")
99		);
100		assert_eq!(
101			PathExt::create_relative("foo/bar/src", "foo/bar/Cargo.toml")
102				.unwrap(),
103			PathBuf::from("../Cargo.toml")
104		);
105	}
106}