1+ use std:: ffi:: OsStr ;
12use std:: path:: { Component , Path , PathBuf } ;
23
34use crate :: Stack ;
45
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+
541/// Access
642impl Stack {
743 /// Returns the top-level path of the stack.
@@ -62,8 +98,13 @@ impl Stack {
6298 /// `relative` paths are terminal, so point to their designated file or directory.
6399 /// The path is also expected to be normalized, and should not contain extra separators, and must not contain `..`
64100 /// 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 ( ) {
67108 return Err ( std:: io:: Error :: new (
68109 std:: io:: ErrorKind :: Other ,
69110 "empty inputs are not allowed" ,
@@ -73,15 +114,19 @@ impl Stack {
73114 delegate. push_directory ( self ) ?;
74115 }
75116
76- let mut components = relative. components ( ) . peekable ( ) ;
77117 let mut existing_components = self . current_relative . components ( ) ;
78118 let mut matching_components = 0 ;
79119 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}" ) ) ) ,
85130 }
86131 }
87132
@@ -100,15 +145,7 @@ impl Stack {
100145 }
101146
102147 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) ?;
112149 let is_last_component = components. peek ( ) . is_none ( ) ;
113150 self . current_is_directory = !is_last_component;
114151 self . current . push ( comp) ;
0 commit comments