1
+ use std:: ffi:: OsStr ;
1
2
use std:: path:: { Component , Path , PathBuf } ;
2
3
3
4
use crate :: Stack ;
4
5
6
+ ///
7
+ pub mod to_normal_path_components {
8
+ use std:: ffi:: OsString ;
9
+
10
+ /// The error used in [`ToNormalPathComponents::to_normal_path_components()`](super::ToNormalPathComponents::to_normal_path_components()).
11
+ #[ derive( Debug , thiserror:: Error ) ]
12
+ #[ allow( missing_docs) ]
13
+ pub enum Error {
14
+ #[ error( "Input path \" {path}\" contains relative or absolute components" , path = std:: path:: Path :: new( . 0 . as_os_str( ) ) . display( ) ) ]
15
+ NotANormalComponent ( OsString ) ,
16
+ }
17
+ }
18
+
19
+ /// Obtain an iterator over `OsStr`-components which are normal, none-relative and not absolute.
20
+ pub trait ToNormalPathComponents {
21
+ /// Return an iterator over the normal components of a path, without the separator.
22
+ // TODO(MSRV): turn this into `impl Iterator` once MSRV is 1.75 or higher
23
+ fn to_normal_path_components (
24
+ & self ,
25
+ ) -> Box < dyn Iterator < Item = Result < & OsStr , to_normal_path_components:: Error > > + ' _ > ;
26
+ }
27
+
28
+ impl ToNormalPathComponents for & Path {
29
+ fn to_normal_path_components (
30
+ & self ,
31
+ ) -> Box < dyn Iterator < Item = Result < & OsStr , to_normal_path_components:: Error > > + ' _ > {
32
+ Box :: new ( self . components ( ) . map ( |component| match component {
33
+ Component :: Normal ( os_str) => Ok ( os_str) ,
34
+ _ => Err ( to_normal_path_components:: Error :: NotANormalComponent (
35
+ self . as_os_str ( ) . to_owned ( ) ,
36
+ ) ) ,
37
+ } ) )
38
+ }
39
+ }
40
+
5
41
/// Access
6
42
impl Stack {
7
43
/// Returns the top-level path of the stack.
@@ -62,8 +98,13 @@ impl Stack {
62
98
/// `relative` paths are terminal, so point to their designated file or directory.
63
99
/// The path is also expected to be normalized, and should not contain extra separators, and must not contain `..`
64
100
/// or have leading or trailing slashes (or additionally backslashes on Windows).
65
- pub fn make_relative_path_current ( & mut self , relative : & Path , delegate : & mut dyn Delegate ) -> std:: io:: Result < ( ) > {
66
- if self . valid_components != 0 && relative. as_os_str ( ) . is_empty ( ) {
101
+ pub fn make_relative_path_current (
102
+ & mut self ,
103
+ relative : impl ToNormalPathComponents ,
104
+ delegate : & mut dyn Delegate ,
105
+ ) -> std:: io:: Result < ( ) > {
106
+ let mut components = relative. to_normal_path_components ( ) . peekable ( ) ;
107
+ if self . valid_components != 0 && components. peek ( ) . is_none ( ) {
67
108
return Err ( std:: io:: Error :: new (
68
109
std:: io:: ErrorKind :: Other ,
69
110
"empty inputs are not allowed" ,
@@ -73,15 +114,19 @@ impl Stack {
73
114
delegate. push_directory ( self ) ?;
74
115
}
75
116
76
- let mut components = relative. components ( ) . peekable ( ) ;
77
117
let mut existing_components = self . current_relative . components ( ) ;
78
118
let mut matching_components = 0 ;
79
119
while let ( Some ( existing_comp) , Some ( new_comp) ) = ( existing_components. next ( ) , components. peek ( ) ) {
80
- if existing_comp == * new_comp {
81
- components. next ( ) ;
82
- matching_components += 1 ;
83
- } else {
84
- break ;
120
+ match new_comp {
121
+ Ok ( new_comp) => {
122
+ if existing_comp. as_os_str ( ) == * new_comp {
123
+ components. next ( ) ;
124
+ matching_components += 1 ;
125
+ } else {
126
+ break ;
127
+ }
128
+ }
129
+ Err ( err) => return Err ( std:: io:: Error :: other ( format ! ( "{err}" ) ) ) ,
85
130
}
86
131
}
87
132
@@ -100,15 +145,7 @@ impl Stack {
100
145
}
101
146
102
147
while let Some ( comp) = components. next ( ) {
103
- if !matches ! ( comp, Component :: Normal ( _) ) {
104
- return Err ( std:: io:: Error :: new (
105
- std:: io:: ErrorKind :: Other ,
106
- format ! (
107
- "Input path \" {}\" contains relative or absolute components" ,
108
- relative. display( )
109
- ) ,
110
- ) ) ;
111
- }
148
+ let comp = comp. map_err ( std:: io:: Error :: other) ?;
112
149
let is_last_component = components. peek ( ) . is_none ( ) ;
113
150
self . current_is_directory = !is_last_component;
114
151
self . current . push ( comp) ;
0 commit comments