lune_utils/
path.rs

1use std::{
2    env::{current_dir, current_exe},
3    path::{MAIN_SEPARATOR, Path, PathBuf},
4    sync::{Arc, LazyLock},
5};
6
7use path_clean::PathClean;
8
9static CWD: LazyLock<Arc<Path>> = LazyLock::new(create_cwd);
10static EXE: LazyLock<Arc<Path>> = LazyLock::new(create_exe);
11
12fn create_cwd() -> Arc<Path> {
13    let mut cwd = current_dir()
14        .expect("failed to find current working directory")
15        .to_str()
16        .expect("current working directory is not valid UTF-8")
17        .to_string();
18    if !cwd.ends_with(MAIN_SEPARATOR) {
19        cwd.push(MAIN_SEPARATOR);
20    }
21    dunce::canonicalize(cwd)
22        .expect("failed to canonicalize current working directory")
23        .into()
24}
25
26fn create_exe() -> Arc<Path> {
27    let exe = current_exe()
28        .expect("failed to find current executable")
29        .to_str()
30        .expect("current executable path is not valid UTF-8")
31        .to_string();
32    dunce::canonicalize(exe)
33        .expect("failed to canonicalize current executable path")
34        .into()
35}
36
37/**
38    Gets the current working directory as an absolute path.
39
40    This absolute path is canonicalized and does not contain any `.` or `..`
41    components, and it is also in a friendly (non-UNC) format.
42
43    This path is also guaranteed to:
44
45    - Be valid UTF-8.
46    - End with the platform's main path separator.
47*/
48#[must_use]
49pub fn get_current_dir() -> Arc<Path> {
50    Arc::clone(&CWD)
51}
52
53/**
54    Gets the path to the current executable as an absolute path.
55
56    This absolute path is canonicalized and does not contain any `.` or `..`
57    components, and it is also in a friendly (non-UNC) format.
58
59    This path is also guaranteed to:
60
61    - Be valid UTF-8.
62*/
63#[must_use]
64pub fn get_current_exe() -> Arc<Path> {
65    Arc::clone(&EXE)
66}
67
68/**
69    Cleans a path.
70
71    See the [`path_clean`] crate for more information on what cleaning a path does.
72*/
73pub fn clean_path(path: impl AsRef<Path>) -> PathBuf {
74    path.as_ref().clean()
75}
76
77/**
78    Makes a path absolute, if it is relative, and then cleans it.
79
80    Relative paths are resolved against the current working directory.
81
82    See the [`path_clean`] crate for more information on what cleaning a path does.
83*/
84pub fn clean_path_and_make_absolute(path: impl AsRef<Path>) -> PathBuf {
85    let path = path.as_ref();
86    if path.is_relative() {
87        CWD.join(path).clean()
88    } else {
89        path.clean()
90    }
91}