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",
"omnipath",
"pwd",
"ref-cast",
]
[[package]]

View File

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

View File

@ -14,7 +14,7 @@ mod private {
}
/// 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:
/// - [`Any`]: a path with no invariants. It may be a relative or an absolute path.
/// - [`Relative`]: a strictly relative path.

View File

@ -2,6 +2,7 @@ use crate::form::{
Absolute, Any, Canonical, IsAbsolute, MaybeRelative, PathCast, PathForm, PathJoin, PathPush,
PathSet, Relative,
};
use ref_cast::{ref_cast_custom, RefCastCustom};
use std::{
borrow::{Borrow, Cow},
cmp::Ordering,
@ -45,8 +46,9 @@ use std::{
/// 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
/// is not the case after using [`as_relative_std_path`](Path::as_relative_std_path).
#[derive(RefCastCustom)]
#[repr(transparent)]
pub struct Path<Form: PathForm = Any> {
pub struct Path<Form = Any> {
_form: PhantomData<Form>,
inner: std::path::Path,
}
@ -162,11 +164,11 @@ impl<Form: PathForm> Path<Form> {
/// Create a new path of any form without validating invariants.
#[inline]
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));
// Safety: `Path<Form>` is a repr(transparent) wrapper around `std::path::Path`.
let path = std::path::Path::new(path.as_ref());
let ptr = std::ptr::from_ref(path) as *const Self;
unsafe { &*ptr }
ref_cast(std::path::Path::new(path))
}
/// 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 {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
// Safety: `Path<Form>` is a repr(transparent) wrapper around `std::path::Path`.
let path: &mut std::path::Path = &mut self.inner;
let ptr = std::ptr::from_mut(path) as *mut Path;
unsafe { &mut *ptr }
#[ref_cast_custom]
fn ref_cast<Form: PathForm>(path: &mut std::path::Path) -> &mut Path<Form>;
ref_cast(&mut self.inner)
}
}