gix_path/
relative_path.rs1use std::path::Path;
2
3use bstr::{BStr, BString, ByteSlice};
4use gix_validate::path::component::Options;
5
6use crate::{os_str_into_bstr, try_from_bstr, try_from_byte_slice};
7
8pub(super) mod types {
9 use bstr::{BStr, ByteSlice};
10 #[derive()]
16 pub struct RelativePath {
17 inner: BStr,
18 }
19
20 impl AsRef<[u8]> for RelativePath {
21 #[inline]
22 fn as_ref(&self) -> &[u8] {
23 self.inner.as_bytes()
24 }
25 }
26}
27use types::RelativePath;
28
29impl RelativePath {
30 fn new_unchecked(value: &BStr) -> Result<&RelativePath, Error> {
31 #[allow(unsafe_code)]
33 unsafe {
34 std::mem::transmute(value)
35 }
36 }
37}
38
39#[derive(Debug, thiserror::Error)]
41#[allow(missing_docs)]
42pub enum Error {
43 #[error("A RelativePath is not allowed to be absolute")]
44 IsAbsolute,
45 #[error(transparent)]
46 ContainsInvalidComponent(#[from] gix_validate::path::component::Error),
47 #[error(transparent)]
48 IllegalUtf8(#[from] crate::Utf8Error),
49}
50
51fn relative_path_from_value_and_path<'a>(path_bstr: &'a BStr, path: &Path) -> Result<&'a RelativePath, Error> {
52 if path.is_absolute() {
53 return Err(Error::IsAbsolute);
54 }
55
56 let options = Options::default();
57
58 for component in path.components() {
59 let component = os_str_into_bstr(component.as_os_str())?;
60 gix_validate::path::component(component, None, options)?;
61 }
62
63 RelativePath::new_unchecked(BStr::new(path_bstr.as_bytes()))
64}
65
66impl<'a> TryFrom<&'a str> for &'a RelativePath {
67 type Error = Error;
68
69 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
70 relative_path_from_value_and_path(value.into(), Path::new(value))
71 }
72}
73
74impl<'a> TryFrom<&'a BStr> for &'a RelativePath {
75 type Error = Error;
76
77 fn try_from(value: &'a BStr) -> Result<Self, Self::Error> {
78 let path = try_from_bstr(value)?;
79 relative_path_from_value_and_path(value, &path)
80 }
81}
82
83impl<'a> TryFrom<&'a [u8]> for &'a RelativePath {
84 type Error = Error;
85
86 #[inline]
87 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
88 let path = try_from_byte_slice(value)?;
89 relative_path_from_value_and_path(value.as_bstr(), path)
90 }
91}
92
93impl<'a, const N: usize> TryFrom<&'a [u8; N]> for &'a RelativePath {
94 type Error = Error;
95
96 #[inline]
97 fn try_from(value: &'a [u8; N]) -> Result<Self, Self::Error> {
98 let path = try_from_byte_slice(value.as_bstr())?;
99 relative_path_from_value_and_path(value.as_bstr(), path)
100 }
101}
102
103impl<'a> TryFrom<&'a BString> for &'a RelativePath {
104 type Error = Error;
105
106 fn try_from(value: &'a BString) -> Result<Self, Self::Error> {
107 let path = try_from_bstr(value.as_bstr())?;
108 relative_path_from_value_and_path(value.as_bstr(), &path)
109 }
110}