mirror of
https://github.com/nushell/nushell.git
synced 2025-02-01 11:09:49 +01:00
Use std::sync::OnceLock which eliminates unsafe code
This commit is contained in:
parent
825396baed
commit
c3b84abbf4
@ -1,6 +1,97 @@
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub mod _impl {
|
pub mod _impl {
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
/// Usage for pwd_per_drive on windows
|
||||||
|
///
|
||||||
|
/// Upon change PWD, call set_pwd_per_drive() with absolute path
|
||||||
|
///
|
||||||
|
/// Call expand_pwd_per_drive() with relative path to get absolution path
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::path::{Path, PathBuf};
|
||||||
|
/// use nu_path::{expand_pwd, set_pwd};
|
||||||
|
///
|
||||||
|
/// // Set PWD for drive C
|
||||||
|
/// set_pwd(Path::new(r"C:\Users\Home")).unwrap();
|
||||||
|
///
|
||||||
|
/// // Expand a relative path
|
||||||
|
/// let expanded = expand_pwd(Path::new("C:test"));
|
||||||
|
/// assert_eq!(expanded, Some(PathBuf::from(r"C:\Users\Home\test")));
|
||||||
|
///
|
||||||
|
/// // Will NOT expand an absolute path
|
||||||
|
/// let expanded = expand_pwd(Path::new(r"C:\absolute\path"));
|
||||||
|
/// assert_eq!(expanded, None);
|
||||||
|
///
|
||||||
|
/// // Expand with no drive letter
|
||||||
|
/// let expanded = expand_pwd(Path::new(r"\no_drive"));
|
||||||
|
/// assert_eq!(expanded, None);
|
||||||
|
///
|
||||||
|
/// // Expand with no PWD set for the drive
|
||||||
|
/// let expanded = expand_pwd(Path::new("D:test"));
|
||||||
|
/// assert_eq!(expanded, Some(PathBuf::from(r"D:\test")));
|
||||||
|
/// ```
|
||||||
|
pub mod singleton {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// set_pwd_per_drive
|
||||||
|
/// Record PWD for drive, path must be absolute path
|
||||||
|
/// return Ok(()) if succeeded, otherwise error message
|
||||||
|
pub fn set_pwd(_path: &Path) -> Result<(), String> {
|
||||||
|
if let Ok(mut pwd_per_drive) = get_drive_pwd_map().lock() {
|
||||||
|
pwd_per_drive.set_pwd(_path)
|
||||||
|
} else {
|
||||||
|
Err("Failed to lock map".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// expand_pwe_per_drive
|
||||||
|
/// Input relative path, expand PWD-per-drive to construct absolute path
|
||||||
|
/// return PathBuf for absolute path, None if input path is invalid.
|
||||||
|
pub fn expand_pwd(_path: &Path) -> Option<PathBuf> {
|
||||||
|
if need_expand_pwd_per_drive(_path) {
|
||||||
|
if let Ok(mut pwd_per_drive) = get_drive_pwd_map().lock() {
|
||||||
|
return pwd_per_drive.expand_path(_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper only used on Windows, if input path is relative path
|
||||||
|
/// with drive letter, it can be expanded with PWD-per-drive.
|
||||||
|
fn need_expand_pwd_per_drive(_path: &Path) -> bool {
|
||||||
|
if let Some(path_str) = _path.to_str() {
|
||||||
|
let chars: Vec<char> = path_str.chars().collect();
|
||||||
|
if chars.len() >= 2 {
|
||||||
|
return chars[1] == ':'
|
||||||
|
&& (chars.len() == 2 || (chars[2] != '/' && chars[2] != '\\'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_usage_for_pwd_per_drive() {
|
||||||
|
use super::_impl::singleton::{expand_pwd, set_pwd};
|
||||||
|
// Set PWD for drive F
|
||||||
|
assert!(set_pwd(Path::new(r"F:\Users\Home")).is_ok());
|
||||||
|
|
||||||
|
// Expand a relative path
|
||||||
|
let expanded = expand_pwd(Path::new("f:test"));
|
||||||
|
assert_eq!(expanded, Some(PathBuf::from(r"F:\Users\Home\test")));
|
||||||
|
|
||||||
|
// Will NOT expand an absolute path
|
||||||
|
let expanded = expand_pwd(Path::new(r"F:\absolute\path"));
|
||||||
|
assert_eq!(expanded, None);
|
||||||
|
|
||||||
|
// Expand with no drive letter
|
||||||
|
let expanded = expand_pwd(Path::new(r"\no_drive"));
|
||||||
|
assert_eq!(expanded, None);
|
||||||
|
|
||||||
|
// Expand with no PWD set for the drive
|
||||||
|
let expanded = expand_pwd(Path::new("G:test"));
|
||||||
|
assert_eq!(expanded, Some(PathBuf::from(r"G:\test")));
|
||||||
|
}
|
||||||
|
|
||||||
struct Drive2PWD {
|
struct Drive2PWD {
|
||||||
map: [Option<String>; 26], // Fixed-size array for A-Z
|
map: [Option<String>; 26], // Fixed-size array for A-Z
|
||||||
@ -91,20 +182,14 @@ pub mod _impl {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Global singleton instance of DrivePwdMap
|
use std::sync::{Mutex, OnceLock};
|
||||||
use std::sync::{Mutex, Once};
|
|
||||||
|
|
||||||
static INIT: Once = Once::new();
|
/// Global singleton instance of DrivePwdMap
|
||||||
static mut DRIVE_PWD_MAP: Option<Mutex<Drive2PWD>> = None;
|
static DRIVE_PWD_MAP: OnceLock<Mutex<Drive2PWD>> = OnceLock::new();
|
||||||
|
|
||||||
/// Access the singleton instance
|
/// Access the singleton instance
|
||||||
fn get_drive_pwd_map() -> &'static Mutex<Drive2PWD> {
|
fn get_drive_pwd_map() -> &'static Mutex<Drive2PWD> {
|
||||||
unsafe {
|
DRIVE_PWD_MAP.get_or_init(|| Mutex::new(Drive2PWD::new()))
|
||||||
INIT.call_once(|| {
|
|
||||||
DRIVE_PWD_MAP = Some(Mutex::new(Drive2PWD::new()));
|
|
||||||
});
|
|
||||||
DRIVE_PWD_MAP.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test for Drive2PWD map
|
/// Test for Drive2PWD map
|
||||||
@ -226,95 +311,4 @@ pub mod _impl {
|
|||||||
assert_eq!(drive_map.get_pwd('1'), None);
|
assert_eq!(drive_map.get_pwd('1'), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Usage for pwd_per_drive on windows
|
|
||||||
///
|
|
||||||
/// Upon change PWD, call set_pwd_per_drive() with absolute path
|
|
||||||
///
|
|
||||||
/// Call expand_pwd_per_drive() with relative path to get absolution path
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::path::{Path, PathBuf};
|
|
||||||
/// use nu_path::{expand_pwd, set_pwd};
|
|
||||||
///
|
|
||||||
/// // Set PWD for drive C
|
|
||||||
/// set_pwd(Path::new(r"C:\Users\Home")).unwrap();
|
|
||||||
///
|
|
||||||
/// // Expand a relative path
|
|
||||||
/// let expanded = expand_pwd(Path::new("C:test"));
|
|
||||||
/// assert_eq!(expanded, Some(PathBuf::from(r"C:\Users\Home\test")));
|
|
||||||
///
|
|
||||||
/// // Will NOT expand an absolute path
|
|
||||||
/// let expanded = expand_pwd(Path::new(r"C:\absolute\path"));
|
|
||||||
/// assert_eq!(expanded, None);
|
|
||||||
///
|
|
||||||
/// // Expand with no drive letter
|
|
||||||
/// let expanded = expand_pwd(Path::new(r"\no_drive"));
|
|
||||||
/// assert_eq!(expanded, None);
|
|
||||||
///
|
|
||||||
/// // Expand with no PWD set for the drive
|
|
||||||
/// let expanded = expand_pwd(Path::new("D:test"));
|
|
||||||
/// assert_eq!(expanded, Some(PathBuf::from(r"D:\test")));
|
|
||||||
/// ```
|
|
||||||
pub mod singleton {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// set_pwd_per_drive
|
|
||||||
/// Record PWD for drive, path must be absolute path
|
|
||||||
/// return Ok(()) if succeeded, otherwise error message
|
|
||||||
pub fn set_pwd(_path: &Path) -> Result<(), String> {
|
|
||||||
if let Ok(mut pwd_per_drive) = get_drive_pwd_map().lock() {
|
|
||||||
pwd_per_drive.set_pwd(_path)
|
|
||||||
} else {
|
|
||||||
Err("Failed to lock map".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// expand_pwe_per_drive
|
|
||||||
/// Input relative path, expand PWD-per-drive to construct absolute path
|
|
||||||
/// return PathBuf for absolute path, None if input path is invalid.
|
|
||||||
pub fn expand_pwd(_path: &Path) -> Option<PathBuf> {
|
|
||||||
if need_expand_pwd_per_drive(_path) {
|
|
||||||
if let Ok(mut pwd_per_drive) = get_drive_pwd_map().lock() {
|
|
||||||
return pwd_per_drive.expand_path(_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper only used on Windows, if input path is relative path
|
|
||||||
/// with drive letter, it can be expanded with PWD-per-drive.
|
|
||||||
fn need_expand_pwd_per_drive(_path: &Path) -> bool {
|
|
||||||
if let Some(path_str) = _path.to_str() {
|
|
||||||
let chars: Vec<char> = path_str.chars().collect();
|
|
||||||
if chars.len() >= 2 {
|
|
||||||
return chars[1] == ':'
|
|
||||||
&& (chars.len() == 2 || (chars[2] != '/' && chars[2] != '\\'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_usage_for_pwd_per_drive() {
|
|
||||||
// Set PWD for drive F
|
|
||||||
assert!(set_pwd(Path::new(r"F:\Users\Home")).is_ok());
|
|
||||||
|
|
||||||
// Expand a relative path
|
|
||||||
let expanded = expand_pwd(Path::new("f:test"));
|
|
||||||
assert_eq!(expanded, Some(PathBuf::from(r"F:\Users\Home\test")));
|
|
||||||
|
|
||||||
// Will NOT expand an absolute path
|
|
||||||
let expanded = expand_pwd(Path::new(r"F:\absolute\path"));
|
|
||||||
assert_eq!(expanded, None);
|
|
||||||
|
|
||||||
// Expand with no drive letter
|
|
||||||
let expanded = expand_pwd(Path::new(r"\no_drive"));
|
|
||||||
assert_eq!(expanded, None);
|
|
||||||
|
|
||||||
// Expand with no PWD set for the drive
|
|
||||||
let expanded = expand_pwd(Path::new("G:test"));
|
|
||||||
assert_eq!(expanded, Some(PathBuf::from(r"G:\test")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user