Use ref-cast crate to remove some unsafe (#14897)

# Description

In a few places, `nu-path` uses `unsafe` to do reference casts. This PR
adds the [`ref-cast`](https://crates.io/crates/ref-cast) crate to do
reference casts in a "safe" manner.
This commit is contained in:
Ian Manske 2025-01-26 20:43:45 +00:00 committed by GitHub
parent f46f8b286b
commit 7ea4895513
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 15 additions and 11 deletions

1
Cargo.lock generated
View File

@ -3928,6 +3928,7 @@ dependencies = [
"dirs", "dirs",
"omnipath", "omnipath",
"pwd", "pwd",
"ref-cast",
] ]
[[package]] [[package]]

View File

@ -13,6 +13,7 @@ bench = false
[dependencies] [dependencies]
dirs = { workspace = true } dirs = { workspace = true }
ref-cast = "1.0.23"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
omnipath = { workspace = true } omnipath = { workspace = true }

View File

@ -14,7 +14,7 @@ mod private {
} }
/// A marker trait for the different kinds of path forms. /// A marker trait for the different kinds of path forms.
/// Each form has its own invariants that are guaranteed be upheld. /// Each form has its own invariants that are guaranteed to be upheld.
/// The list of path forms are: /// The list of path forms are:
/// - [`Any`]: a path with no invariants. It may be a relative or an absolute path. /// - [`Any`]: a path with no invariants. It may be a relative or an absolute path.
/// - [`Relative`]: a strictly relative path. /// - [`Relative`]: a strictly relative path.

View File

@ -2,6 +2,7 @@ use crate::form::{
Absolute, Any, Canonical, IsAbsolute, MaybeRelative, PathCast, PathForm, PathJoin, PathPush, Absolute, Any, Canonical, IsAbsolute, MaybeRelative, PathCast, PathForm, PathJoin, PathPush,
PathSet, Relative, PathSet, Relative,
}; };
use ref_cast::{ref_cast_custom, RefCastCustom};
use std::{ use std::{
borrow::{Borrow, Cow}, borrow::{Borrow, Cow},
cmp::Ordering, cmp::Ordering,
@ -45,8 +46,9 @@ use std::{
/// But this may cause third-party code to use [`std::env::current_dir`] to resolve /// But this may cause third-party code to use [`std::env::current_dir`] to resolve
/// the path which is almost always incorrect behavior. Extra care is needed to ensure that this /// the path which is almost always incorrect behavior. Extra care is needed to ensure that this
/// is not the case after using [`as_relative_std_path`](Path::as_relative_std_path). /// is not the case after using [`as_relative_std_path`](Path::as_relative_std_path).
#[derive(RefCastCustom)]
#[repr(transparent)] #[repr(transparent)]
pub struct Path<Form: PathForm = Any> { pub struct Path<Form = Any> {
_form: PhantomData<Form>, _form: PhantomData<Form>,
inner: std::path::Path, inner: std::path::Path,
} }
@ -162,11 +164,11 @@ impl<Form: PathForm> Path<Form> {
/// Create a new path of any form without validating invariants. /// Create a new path of any form without validating invariants.
#[inline] #[inline]
fn new_unchecked<P: AsRef<OsStr> + ?Sized>(path: &P) -> &Self { fn new_unchecked<P: AsRef<OsStr> + ?Sized>(path: &P) -> &Self {
#[ref_cast_custom]
fn ref_cast<Form: PathForm>(path: &std::path::Path) -> &Path<Form>;
debug_assert!(Form::invariants_satisfied(path)); debug_assert!(Form::invariants_satisfied(path));
// Safety: `Path<Form>` is a repr(transparent) wrapper around `std::path::Path`. ref_cast(std::path::Path::new(path))
let path = std::path::Path::new(path.as_ref());
let ptr = std::ptr::from_ref(path) as *const Self;
unsafe { &*ptr }
} }
/// Attempt to create a new [`Path`] from a reference of another type. /// Attempt to create a new [`Path`] from a reference of another type.
@ -1900,10 +1902,10 @@ impl<Form: PathForm> Deref for PathBuf<Form> {
impl DerefMut for PathBuf { impl DerefMut for PathBuf {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
// Safety: `Path<Form>` is a repr(transparent) wrapper around `std::path::Path`. #[ref_cast_custom]
let path: &mut std::path::Path = &mut self.inner; fn ref_cast<Form: PathForm>(path: &mut std::path::Path) -> &mut Path<Form>;
let ptr = std::ptr::from_mut(path) as *mut Path;
unsafe { &mut *ptr } ref_cast(&mut self.inner)
} }
} }