@@ -2,21 +2,32 @@ use bstr::BStr;
2
2
use bstr:: BString ;
3
3
use bstr:: ByteSlice ;
4
4
use gix_validate:: path:: component:: Options ;
5
- use std:: borrow :: Cow ;
5
+ use std:: path :: Path ;
6
6
7
7
use crate :: os_str_into_bstr;
8
8
use crate :: try_from_bstr;
9
9
use crate :: try_from_byte_slice;
10
10
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
+ }
19
29
}
30
+ use types:: RelativePath ;
20
31
21
32
impl RelativePath {
22
33
fn new_unchecked ( value : & BStr ) -> Result < & RelativePath , Error > {
@@ -26,12 +37,6 @@ impl RelativePath {
26
37
std:: mem:: transmute ( value)
27
38
}
28
39
}
29
-
30
- /// TODO
31
- /// Needs docs.
32
- pub fn ends_with ( & self , needle : & [ u8 ] ) -> bool {
33
- self . inner . ends_with ( needle)
34
- }
35
40
}
36
41
37
42
/// The error used in [`RelativePath`].
@@ -46,49 +51,45 @@ pub enum Error {
46
51
IllegalUtf8 ( #[ from] crate :: Utf8Error ) ,
47
52
}
48
53
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
+ }
54
58
55
- let path : & std :: path :: Path = Path :: new ( value ) ;
59
+ let options = Options :: default ( ) ;
56
60
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
+ }
62
65
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
+ }
65
68
66
- gix_validate :: path :: component ( component , None , options ) ? ;
67
- }
69
+ impl < ' a > TryFrom < & ' a str > for & ' a RelativePath {
70
+ type Error = Error ;
68
71
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) )
70
74
}
71
75
}
72
76
73
77
impl < ' a > TryFrom < & ' a BStr > for & ' a RelativePath {
74
78
type Error = Error ;
75
79
76
80
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
+ }
87
85
88
- gix_validate :: path :: component ( component , None , options ) ? ;
89
- }
86
+ impl < ' a > TryFrom < & ' a [ u8 ] > for & ' a RelativePath {
87
+ type Error = Error ;
90
88
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)
92
93
}
93
94
}
94
95
@@ -97,218 +98,16 @@ impl<'a, const N: usize> TryFrom<&'a [u8; N]> for &'a RelativePath {
97
98
98
99
#[ inline]
99
100
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)
115
103
}
116
104
}
117
105
118
106
impl < ' a > TryFrom < & ' a BString > for & ' a RelativePath {
119
107
type Error = Error ;
120
108
121
109
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)
313
112
}
314
113
}
0 commit comments