From 7ea489551315a5ab68fd1e9e5a7ed5a0b3ef494a Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Sun, 26 Jan 2025 20:43:45 +0000 Subject: [PATCH] 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. --- Cargo.lock | 1 + crates/nu-path/Cargo.toml | 3 ++- crates/nu-path/src/form.rs | 2 +- crates/nu-path/src/path.rs | 20 +++++++++++--------- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22d0e50d33..4ac27d4dd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3928,6 +3928,7 @@ dependencies = [ "dirs", "omnipath", "pwd", + "ref-cast", ] [[package]] diff --git a/crates/nu-path/Cargo.toml b/crates/nu-path/Cargo.toml index 155e4168c9..ad64a0a4aa 100644 --- a/crates/nu-path/Cargo.toml +++ b/crates/nu-path/Cargo.toml @@ -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 \ No newline at end of file +workspace = true diff --git a/crates/nu-path/src/form.rs b/crates/nu-path/src/form.rs index edec72c08c..260db74540 100644 --- a/crates/nu-path/src/form.rs +++ b/crates/nu-path/src/form.rs @@ -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. diff --git a/crates/nu-path/src/path.rs b/crates/nu-path/src/path.rs index 9d7b64af27..69b370a374 100644 --- a/crates/nu-path/src/path.rs +++ b/crates/nu-path/src/path.rs @@ -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 { +pub struct Path
{ _form: PhantomData, inner: std::path::Path, } @@ -162,11 +164,11 @@ impl Path { /// Create a new path of any form without validating invariants. #[inline] fn new_unchecked + ?Sized>(path: &P) -> &Self { + #[ref_cast_custom] + fn ref_cast(path: &std::path::Path) -> &Path; + debug_assert!(Form::invariants_satisfied(path)); - // Safety: `Path` 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 Deref for PathBuf { impl DerefMut for PathBuf { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { - // Safety: `Path` 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(path: &mut std::path::Path) -> &mut Path; + + ref_cast(&mut self.inner) } }