Add debug asserts

This commit is contained in:
Ian Manske 2024-06-22 11:04:53 -07:00
parent f0be6ddc08
commit 670f77be9b
2 changed files with 39 additions and 11 deletions

View File

@ -1,10 +1,16 @@
use std::ffi::OsStr;
mod private { mod private {
use std::ffi::OsStr;
// This trait should not be extended by external crates in order to uphold safety guarantees. // This trait should not be extended by external crates in order to uphold safety guarantees.
// As such, this trait is put inside a private module to prevent external impls. // As such, this trait is put inside a private module to prevent external impls.
// This ensures that all possible [`PathForm`]s can only be defined here and will: // This ensures that all possible [`PathForm`]s can only be defined here and will:
// - be zero sized (enforced anyways by the `repr(transparent)` on `Path`) // - be zero sized (enforced anyways by the `repr(transparent)` on `Path`)
// - have a no-op [`Drop`] implementation // - have a no-op [`Drop`] implementation
pub trait Sealed {} pub trait Sealed {
fn invariants_satisfied<P: AsRef<OsStr> + ?Sized>(path: &P) -> bool;
}
} }
/// A marker trait for the different kinds of path forms. /// A marker trait for the different kinds of path forms.
@ -26,7 +32,11 @@ impl PathForm for Canonical {}
/// trailing slashes, dot components (`..` or `.`), and repeated path separators. /// trailing slashes, dot components (`..` or `.`), and repeated path separators.
pub struct Any; pub struct Any;
impl private::Sealed for Any {} impl private::Sealed for Any {
fn invariants_satisfied<P: AsRef<OsStr> + ?Sized>(_: &P) -> bool {
true
}
}
/// A strictly relative path. /// A strictly relative path.
/// ///
@ -34,7 +44,11 @@ impl private::Sealed for Any {}
/// trailing slashes, dot components (`..` or `.`), and repeated path separators. /// trailing slashes, dot components (`..` or `.`), and repeated path separators.
pub struct Relative; pub struct Relative;
impl private::Sealed for Relative {} impl private::Sealed for Relative {
fn invariants_satisfied<P: AsRef<OsStr> + ?Sized>(path: &P) -> bool {
std::path::Path::new(path).is_relative()
}
}
/// An absolute path. /// An absolute path.
/// ///
@ -42,14 +56,22 @@ impl private::Sealed for Relative {}
/// trailing slashes, dot components (`..` or `.`), and repeated path separators. /// trailing slashes, dot components (`..` or `.`), and repeated path separators.
pub struct Absolute; pub struct Absolute;
impl private::Sealed for Absolute {} impl private::Sealed for Absolute {
fn invariants_satisfied<P: AsRef<OsStr> + ?Sized>(path: &P) -> bool {
std::path::Path::new(path).is_absolute()
}
}
// A canonical path. // A canonical path.
// //
// An absolute path with all intermediate components normalized and symbolic links resolved. // An absolute path with all intermediate components normalized and symbolic links resolved.
pub struct Canonical; pub struct Canonical;
impl private::Sealed for Canonical {} impl private::Sealed for Canonical {
fn invariants_satisfied<P: AsRef<OsStr> + ?Sized>(_: &P) -> bool {
true
}
}
/// A marker trait for [`PathForm`]s that may be relative paths. /// A marker trait for [`PathForm`]s that may be relative paths.
/// This includes only the [`Any`] and [`Relative`] path forms. /// This includes only the [`Any`] and [`Relative`] path forms.

View File

@ -161,6 +161,7 @@ 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 {
debug_assert!(Form::invariants_satisfied(path));
// Safety: `Path<Form>` is a repr(transparent) wrapper around `std::path::Path`. // Safety: `Path<Form>` is a repr(transparent) wrapper around `std::path::Path`.
let path = std::path::Path::new(path.as_ref()); let path = std::path::Path::new(path.as_ref());
let ptr = std::ptr::from_ref(path) as *const Self; let ptr = std::ptr::from_ref(path) as *const Self;
@ -705,9 +706,11 @@ impl Path {
/// ``` /// ```
#[inline] #[inline]
pub fn try_absolute(&self) -> Result<&AbsolutePath, &RelativePath> { pub fn try_absolute(&self) -> Result<&AbsolutePath, &RelativePath> {
self.is_absolute() if self.is_absolute() {
.then_some(AbsolutePath::new_unchecked(&self.inner)) Ok(AbsolutePath::new_unchecked(&self.inner))
.ok_or(RelativePath::new_unchecked(&self.inner)) } else {
Err(RelativePath::new_unchecked(&self.inner))
}
} }
/// Returns an `Ok` [`RelativePath`] if the [`Path`] is relative. /// Returns an `Ok` [`RelativePath`] if the [`Path`] is relative.
@ -722,9 +725,11 @@ impl Path {
/// ``` /// ```
#[inline] #[inline]
pub fn try_relative(&self) -> Result<&RelativePath, &AbsolutePath> { pub fn try_relative(&self) -> Result<&RelativePath, &AbsolutePath> {
self.is_relative() if self.is_relative() {
.then_some(RelativePath::new_unchecked(&self.inner)) Ok(RelativePath::new_unchecked(&self.inner))
.ok_or(AbsolutePath::new_unchecked(&self.inner)) } else {
Err(AbsolutePath::new_unchecked(&self.inner))
}
} }
} }
@ -1372,6 +1377,7 @@ impl<Form: PathForm> PathBuf<Form> {
/// Create a new [`PathBuf`] of any form without validiting invariants. /// Create a new [`PathBuf`] of any form without validiting invariants.
#[inline] #[inline]
pub(crate) fn new_unchecked(buf: std::path::PathBuf) -> Self { pub(crate) fn new_unchecked(buf: std::path::PathBuf) -> Self {
debug_assert!(Form::invariants_satisfied(&buf));
Self { Self {
_form: PhantomData, _form: PhantomData,
inner: buf, inner: buf,