110 lines · 3.2 KB · Rust
RawDownload
use std::path::Path; use bstr::{BStr, BString, ByteSlice};use gix_validate::path::component::Options; use crate::{os_str_into_bstr, try_from_bstr, try_from_byte_slice}; pub(super) mod types {    use bstr::{BStr, ByteSlice};    /// A wrapper for `BStr`. It is used to enforce the following constraints:    ///    /// - The path separator always is `/`, independent of the platform.    /// - Only normal components are allowed.    /// - It is always represented as a bunch of bytes.    #[repr(transparent)]    pub struct RelativePath {        inner: BStr,    }     impl AsRef<[u8]> for RelativePath {        #[inline]        fn as_ref(&self) -> &[u8] {            self.inner.as_bytes()        }    }}use types::RelativePath; impl RelativePath {    fn new_unchecked(value: &BStr) -> Result<&RelativePath, Error> {        // SAFETY: `RelativePath` is transparent and equivalent to a `&BStr` if provided as reference.        #[expect(unsafe_code)]        unsafe {            Ok(std::mem::transmute::<&BStr, &RelativePath>(value))        }    }} /// The error used in [`RelativePath`].#[derive(Debug, thiserror::Error)]#[expect(missing_docs)]pub enum Error {    #[error("A RelativePath is not allowed to be absolute")]    IsAbsolute,    #[error(transparent)]    ContainsInvalidComponent(#[from] gix_validate::path::component::Error),    #[error(transparent)]    IllegalUtf8(#[from] crate::Utf8Error),} fn relative_path_from_value_and_path<'a>(path_bstr: &'a BStr, path: &Path) -> Result<&'a RelativePath, Error> {    if path.is_absolute() {        return Err(Error::IsAbsolute);    }     let options = Options::default();     for component in path.components() {        let component = os_str_into_bstr(component.as_os_str())?;        gix_validate::path::component(component, None, options)?;    }     RelativePath::new_unchecked(BStr::new(path_bstr.as_bytes()))} impl<'a> TryFrom<&'a str> for &'a RelativePath {    type Error = Error;     fn try_from(value: &'a str) -> Result<Self, Self::Error> {        relative_path_from_value_and_path(value.into(), Path::new(value))    }} impl<'a> TryFrom<&'a BStr> for &'a RelativePath {    type Error = Error;     fn try_from(value: &'a BStr) -> Result<Self, Self::Error> {        let path = try_from_bstr(value)?;        relative_path_from_value_and_path(value, &path)    }} impl<'a> TryFrom<&'a [u8]> for &'a RelativePath {    type Error = Error;     #[inline]    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {        let path = try_from_byte_slice(value)?;        relative_path_from_value_and_path(value.as_bstr(), path)    }} impl<'a, const N: usize> TryFrom<&'a [u8; N]> for &'a RelativePath {    type Error = Error;     #[inline]    fn try_from(value: &'a [u8; N]) -> Result<Self, Self::Error> {        let path = try_from_byte_slice(value.as_bstr())?;        relative_path_from_value_and_path(value.as_bstr(), path)    }} impl<'a> TryFrom<&'a BString> for &'a RelativePath {    type Error = Error;     fn try_from(value: &'a BString) -> Result<Self, Self::Error> {        let path = try_from_bstr(value.as_bstr())?;        relative_path_from_value_and_path(value.as_bstr(), &path)    }}