@@ -2,21 +2,32 @@ use bstr::BStr;
22use bstr:: BString ;
33use bstr:: ByteSlice ;
44use gix_validate:: path:: component:: Options ;
5- use std:: borrow :: Cow ;
5+ use std:: path :: Path ;
66
77use crate :: os_str_into_bstr;
88use crate :: try_from_bstr;
99use crate :: try_from_byte_slice;
1010
11- /// A wrapper for `BStr`. It is used to enforce the following constraints:
12- ///
13- /// - The path separator always is `/`, independent of the platform.
14- /// - Only normal components are allowed.
15- /// - It is always represented as a bunch of bytes.
16- #[ derive( ) ]
17- pub struct RelativePath {
18- inner : BStr ,
11+ pub ( super ) mod types {
12+ use bstr:: { BStr , ByteSlice } ;
13+ /// A wrapper for `BStr`. It is used to enforce the following constraints:
14+ ///
15+ /// - The path separator always is `/`, independent of the platform.
16+ /// - Only normal components are allowed.
17+ /// - It is always represented as a bunch of bytes.
18+ #[ derive( ) ]
19+ pub struct RelativePath {
20+ inner : BStr ,
21+ }
22+
23+ impl AsRef < [ u8 ] > for RelativePath {
24+ #[ inline]
25+ fn as_ref ( & self ) -> & [ u8 ] {
26+ self . inner . as_bytes ( )
27+ }
28+ }
1929}
30+ use types:: RelativePath ;
2031
2132impl RelativePath {
2233 fn new_unchecked ( value : & BStr ) -> Result < & RelativePath , Error > {
@@ -26,12 +37,6 @@ impl RelativePath {
2637 std:: mem:: transmute ( value)
2738 }
2839 }
29-
30- /// TODO
31- /// Needs docs.
32- pub fn ends_with ( & self , needle : & [ u8 ] ) -> bool {
33- self . inner . ends_with ( needle)
34- }
3540}
3641
3742/// The error used in [`RelativePath`].
@@ -46,49 +51,45 @@ pub enum Error {
4651 IllegalUtf8 ( #[ from] crate :: Utf8Error ) ,
4752}
4853
49- impl < ' a > TryFrom < & ' a str > for & ' a RelativePath {
50- type Error = Error ;
51-
52- fn try_from ( value : & ' a str ) -> Result < Self , Self :: Error > {
53- use std:: path:: Path ;
54+ fn relative_path_from_value_and_path < ' a > ( path_bstr : & ' a BStr , path : & Path ) -> Result < & ' a RelativePath , Error > {
55+ if path. is_absolute ( ) {
56+ return Err ( Error :: IsAbsolute ) ;
57+ }
5458
55- let path : & std :: path :: Path = Path :: new ( value ) ;
59+ let options = Options :: default ( ) ;
5660
57- if path. is_absolute ( ) {
58- return Err ( Error :: IsAbsolute ) ;
59- }
60-
61- let options: Options = Default :: default ( ) ;
61+ for component in path. components ( ) {
62+ let component = os_str_into_bstr ( component. as_os_str ( ) ) ?;
63+ gix_validate:: path:: component ( component, None , options) ?;
64+ }
6265
63- for component in path . components ( ) {
64- let component = os_str_into_bstr ( component . as_os_str ( ) ) ? ;
66+ RelativePath :: new_unchecked ( BStr :: new ( path_bstr . as_bytes ( ) ) )
67+ }
6568
66- gix_validate :: path :: component ( component , None , options ) ? ;
67- }
69+ impl < ' a > TryFrom < & ' a str > for & ' a RelativePath {
70+ type Error = Error ;
6871
69- RelativePath :: new_unchecked ( BStr :: new ( value. as_bytes ( ) ) )
72+ fn try_from ( value : & ' a str ) -> Result < Self , Self :: Error > {
73+ relative_path_from_value_and_path ( value. into ( ) , Path :: new ( value) )
7074 }
7175}
7276
7377impl < ' a > TryFrom < & ' a BStr > for & ' a RelativePath {
7478 type Error = Error ;
7579
7680 fn try_from ( value : & ' a BStr ) -> Result < Self , Self :: Error > {
77- let path: & std:: path:: Path = & try_from_bstr ( value) ?;
78-
79- if path. is_absolute ( ) {
80- return Err ( Error :: IsAbsolute ) ;
81- }
82-
83- let options: Options = Default :: default ( ) ;
84-
85- for component in path. components ( ) {
86- let component = os_str_into_bstr ( component. as_os_str ( ) ) ?;
81+ let path = try_from_bstr ( value) ?;
82+ relative_path_from_value_and_path ( value, & path)
83+ }
84+ }
8785
88- gix_validate :: path :: component ( component , None , options ) ? ;
89- }
86+ impl < ' a > TryFrom < & ' a [ u8 ] > for & ' a RelativePath {
87+ type Error = Error ;
9088
91- RelativePath :: new_unchecked ( value)
89+ #[ inline]
90+ fn try_from ( value : & ' a [ u8 ] ) -> Result < Self , Self :: Error > {
91+ let path = try_from_byte_slice ( value) ?;
92+ relative_path_from_value_and_path ( value. as_bstr ( ) , path)
9293 }
9394}
9495
@@ -97,218 +98,16 @@ impl<'a, const N: usize> TryFrom<&'a [u8; N]> for &'a RelativePath {
9798
9899 #[ inline]
99100 fn try_from ( value : & ' a [ u8 ; N ] ) -> Result < Self , Self :: Error > {
100- let path: & std:: path:: Path = try_from_byte_slice ( value) ?;
101-
102- if path. is_absolute ( ) {
103- return Err ( Error :: IsAbsolute ) ;
104- }
105-
106- let options: Options = Default :: default ( ) ;
107-
108- for component in path. components ( ) {
109- let component = os_str_into_bstr ( component. as_os_str ( ) ) ?;
110-
111- gix_validate:: path:: component ( component, None , options) ?;
112- }
113-
114- RelativePath :: new_unchecked ( value. into ( ) )
101+ let path = try_from_byte_slice ( value. as_bstr ( ) ) ?;
102+ relative_path_from_value_and_path ( value. as_bstr ( ) , path)
115103 }
116104}
117105
118106impl < ' a > TryFrom < & ' a BString > for & ' a RelativePath {
119107 type Error = Error ;
120108
121109 fn try_from ( value : & ' a BString ) -> Result < Self , Self :: Error > {
122- let path: & std:: path:: Path = & try_from_bstr ( value. as_bstr ( ) ) ?;
123-
124- if path. is_absolute ( ) {
125- return Err ( Error :: IsAbsolute ) ;
126- }
127-
128- let options: Options = Default :: default ( ) ;
129-
130- for component in path. components ( ) {
131- let component = os_str_into_bstr ( component. as_os_str ( ) ) ?;
132-
133- gix_validate:: path:: component ( component, None , options) ?;
134- }
135-
136- RelativePath :: new_unchecked ( value. as_bstr ( ) )
137- }
138- }
139-
140- /// This is required by a trait bound on [`from_str`](crate::from_bstr).
141- impl < ' a > From < & ' a RelativePath > for Cow < ' a , BStr > {
142- #[ inline]
143- fn from ( value : & ' a RelativePath ) -> Cow < ' a , BStr > {
144- Cow :: Borrowed ( & value. inner )
145- }
146- }
147-
148- impl AsRef < [ u8 ] > for RelativePath {
149- #[ inline]
150- fn as_ref ( & self ) -> & [ u8 ] {
151- self . inner . as_bytes ( )
152- }
153- }
154-
155- #[ cfg( test) ]
156- mod tests {
157- use super :: * ;
158-
159- #[ cfg( not( windows) ) ]
160- #[ test]
161- fn absolute_paths_return_err ( ) {
162- let path_str: & str = "/refs/heads" ;
163- let path_bstr: & BStr = path_str. into ( ) ;
164- let path_u8: & [ u8 ; 11 ] = b"/refs/heads" ;
165- let path_bstring: BString = "/refs/heads" . into ( ) ;
166-
167- assert ! ( matches!(
168- TryInto :: <& RelativePath >:: try_into( path_str) ,
169- Err ( Error :: IsAbsolute )
170- ) ) ;
171- assert ! ( matches!(
172- TryInto :: <& RelativePath >:: try_into( path_bstr) ,
173- Err ( Error :: IsAbsolute )
174- ) ) ;
175- assert ! ( matches!(
176- TryInto :: <& RelativePath >:: try_into( path_u8) ,
177- Err ( Error :: IsAbsolute )
178- ) ) ;
179- assert ! ( matches!(
180- TryInto :: <& RelativePath >:: try_into( & path_bstring) ,
181- Err ( Error :: IsAbsolute )
182- ) ) ;
183- }
184-
185- #[ cfg( windows) ]
186- #[ test]
187- fn absolute_paths_return_err ( ) {
188- let path_str: & str = r"c:\refs\heads" ;
189- let path_bstr: & BStr = path_str. into ( ) ;
190- let path_u8: & [ u8 ; 13 ] = b"c:\\ refs\\ heads" ;
191- let path_bstring: BString = r"c:\refs\heads" . into ( ) ;
192-
193- assert ! ( matches!(
194- TryInto :: <& RelativePath >:: try_into( path_str) ,
195- Err ( Error :: IsAbsolute )
196- ) ) ;
197- assert ! ( matches!(
198- TryInto :: <& RelativePath >:: try_into( path_bstr) ,
199- Err ( Error :: IsAbsolute )
200- ) ) ;
201- assert ! ( matches!(
202- TryInto :: <& RelativePath >:: try_into( path_u8) ,
203- Err ( Error :: IsAbsolute )
204- ) ) ;
205- assert ! ( matches!(
206- TryInto :: <& RelativePath >:: try_into( & path_bstring) ,
207- Err ( Error :: IsAbsolute )
208- ) ) ;
209- }
210-
211- #[ cfg( not( windows) ) ]
212- #[ test]
213- fn dots_in_paths_return_err ( ) {
214- let path_str: & str = "./heads" ;
215- let path_bstr: & BStr = path_str. into ( ) ;
216- let path_u8: & [ u8 ; 7 ] = b"./heads" ;
217- let path_bstring: BString = "./heads" . into ( ) ;
218-
219- assert ! ( matches!(
220- TryInto :: <& RelativePath >:: try_into( path_str) ,
221- Err ( Error :: ContainsInvalidComponent ( _) )
222- ) ) ;
223- assert ! ( matches!(
224- TryInto :: <& RelativePath >:: try_into( path_bstr) ,
225- Err ( Error :: ContainsInvalidComponent ( _) )
226- ) ) ;
227- assert ! ( matches!(
228- TryInto :: <& RelativePath >:: try_into( path_u8) ,
229- Err ( Error :: ContainsInvalidComponent ( _) )
230- ) ) ;
231- assert ! ( matches!(
232- TryInto :: <& RelativePath >:: try_into( & path_bstring) ,
233- Err ( Error :: ContainsInvalidComponent ( _) )
234- ) ) ;
235- }
236-
237- #[ cfg( windows) ]
238- #[ test]
239- fn dots_in_paths_return_err ( ) {
240- let path_str: & str = r".\heads" ;
241- let path_bstr: & BStr = path_str. into ( ) ;
242- let path_u8: & [ u8 ; 7 ] = b".\\ heads" ;
243- let path_bstring: BString = r".\heads" . into ( ) ;
244-
245- assert ! ( matches!(
246- TryInto :: <& RelativePath >:: try_into( path_str) ,
247- Err ( Error :: ContainsInvalidComponent ( _) )
248- ) ) ;
249- assert ! ( matches!(
250- TryInto :: <& RelativePath >:: try_into( path_bstr) ,
251- Err ( Error :: ContainsInvalidComponent ( _) )
252- ) ) ;
253- assert ! ( matches!(
254- TryInto :: <& RelativePath >:: try_into( path_u8) ,
255- Err ( Error :: ContainsInvalidComponent ( _) )
256- ) ) ;
257- assert ! ( matches!(
258- TryInto :: <& RelativePath >:: try_into( & path_bstring) ,
259- Err ( Error :: ContainsInvalidComponent ( _) )
260- ) ) ;
261- }
262-
263- #[ cfg( not( windows) ) ]
264- #[ test]
265- fn double_dots_in_paths_return_err ( ) {
266- let path_str: & str = "../heads" ;
267- let path_bstr: & BStr = path_str. into ( ) ;
268- let path_u8: & [ u8 ; 8 ] = b"../heads" ;
269- let path_bstring: BString = "../heads" . into ( ) ;
270-
271- assert ! ( matches!(
272- TryInto :: <& RelativePath >:: try_into( path_str) ,
273- Err ( Error :: ContainsInvalidComponent ( _) )
274- ) ) ;
275- assert ! ( matches!(
276- TryInto :: <& RelativePath >:: try_into( path_bstr) ,
277- Err ( Error :: ContainsInvalidComponent ( _) )
278- ) ) ;
279- assert ! ( matches!(
280- TryInto :: <& RelativePath >:: try_into( path_u8) ,
281- Err ( Error :: ContainsInvalidComponent ( _) )
282- ) ) ;
283- assert ! ( matches!(
284- TryInto :: <& RelativePath >:: try_into( & path_bstring) ,
285- Err ( Error :: ContainsInvalidComponent ( _) )
286- ) ) ;
287- }
288-
289- #[ cfg( windows) ]
290- #[ test]
291- fn double_dots_in_paths_return_err ( ) {
292- let path_str: & str = r"..\heads" ;
293- let path_bstr: & BStr = path_str. into ( ) ;
294- let path_u8: & [ u8 ; 8 ] = b"..\\ heads" ;
295- let path_bstring: BString = r"..\heads" . into ( ) ;
296-
297- assert ! ( matches!(
298- TryInto :: <& RelativePath >:: try_into( path_str) ,
299- Err ( Error :: ContainsInvalidComponent ( _) )
300- ) ) ;
301- assert ! ( matches!(
302- TryInto :: <& RelativePath >:: try_into( path_bstr) ,
303- Err ( Error :: ContainsInvalidComponent ( _) )
304- ) ) ;
305- assert ! ( matches!(
306- TryInto :: <& RelativePath >:: try_into( path_u8) ,
307- Err ( Error :: ContainsInvalidComponent ( _) )
308- ) ) ;
309- assert ! ( matches!(
310- TryInto :: <& RelativePath >:: try_into( & path_bstring) ,
311- Err ( Error :: ContainsInvalidComponent ( _) )
312- ) ) ;
110+ let path = try_from_bstr ( value. as_bstr ( ) ) ?;
111+ relative_path_from_value_and_path ( value. as_bstr ( ) , & path)
313112 }
314113}
0 commit comments