@@ -57,30 +57,155 @@ impl VfsPath {
57
57
} ;
58
58
buf. push ( tag) ;
59
59
match & self . 0 {
60
- VfsPathRepr :: PathBuf ( it) => {
61
- let path: & std:: ffi:: OsStr = it. as_os_str ( ) ;
60
+ VfsPathRepr :: PathBuf ( path) => {
62
61
#[ cfg( windows) ]
63
62
{
64
- use std:: os:: windows:: ffi:: OsStrExt ;
65
- for wchar in path. encode_wide ( ) {
66
- buf. extend ( wchar. to_le_bytes ( ) . iter ( ) . copied ( ) ) ;
63
+ use windows_paths:: Encode ;
64
+ let components = path. components ( ) ;
65
+ let mut add_sep = false ;
66
+ for component in components {
67
+ if add_sep {
68
+ windows_paths:: SEP . encode ( buf) ;
69
+ }
70
+ let len_before = buf. len ( ) ;
71
+ match component {
72
+ std:: path:: Component :: Prefix ( prefix) => {
73
+ // kind() returns a normalized and comparable path prefix.
74
+ prefix. kind ( ) . encode ( buf) ;
75
+ }
76
+ std:: path:: Component :: RootDir => {
77
+ if !add_sep {
78
+ component. as_os_str ( ) . encode ( buf) ;
79
+ }
80
+ }
81
+ _ => component. as_os_str ( ) . encode ( buf) ,
82
+ }
83
+
84
+ // some components may be encoded empty
85
+ add_sep = len_before != buf. len ( ) ;
67
86
}
68
87
}
69
88
#[ cfg( unix) ]
70
89
{
71
90
use std:: os:: unix:: ffi:: OsStrExt ;
72
- buf. extend ( path. as_bytes ( ) ) ;
91
+ buf. extend ( path. as_os_str ( ) . as_bytes ( ) ) ;
73
92
}
74
93
#[ cfg( not( any( windows, unix) ) ) ]
75
94
{
76
- buf. extend ( path. to_string_lossy ( ) . as_bytes ( ) ) ;
95
+ buf. extend ( path. as_os_str ( ) . to_string_lossy ( ) . as_bytes ( ) ) ;
77
96
}
78
97
}
79
98
VfsPathRepr :: VirtualPath ( VirtualPath ( s) ) => buf. extend ( s. as_bytes ( ) ) ,
80
99
}
81
100
}
82
101
}
83
102
103
+ #[ cfg( windows) ]
104
+ mod windows_paths {
105
+ pub trait Encode {
106
+ fn encode ( & self , buf : & mut Vec < u8 > ) ;
107
+ }
108
+
109
+ impl Encode for std:: ffi:: OsStr {
110
+ fn encode ( & self , buf : & mut Vec < u8 > ) {
111
+ use std:: os:: windows:: ffi:: OsStrExt ;
112
+ for wchar in self . encode_wide ( ) {
113
+ buf. extend ( wchar. to_le_bytes ( ) . iter ( ) . copied ( ) ) ;
114
+ }
115
+ }
116
+ }
117
+
118
+ impl Encode for u8 {
119
+ fn encode ( & self , buf : & mut Vec < u8 > ) {
120
+ let wide = * self as u16 ;
121
+ buf. extend ( wide. to_le_bytes ( ) . iter ( ) . copied ( ) )
122
+ }
123
+ }
124
+
125
+ impl Encode for & str {
126
+ fn encode ( & self , buf : & mut Vec < u8 > ) {
127
+ debug_assert ! ( self . is_ascii( ) ) ;
128
+ for b in self . as_bytes ( ) {
129
+ b. encode ( buf)
130
+ }
131
+ }
132
+ }
133
+
134
+ pub const SEP : & str = "\\ " ;
135
+ const VERBATIM : & str = "\\ \\ ?\\ " ;
136
+ const UNC : & str = "UNC" ;
137
+ const DEVICE : & str = "\\ \\ .\\ " ;
138
+ const COLON : & str = ":" ;
139
+
140
+ impl Encode for std:: path:: Prefix < ' _ > {
141
+ fn encode ( & self , buf : & mut Vec < u8 > ) {
142
+ match self {
143
+ std:: path:: Prefix :: Verbatim ( c) => {
144
+ VERBATIM . encode ( buf) ;
145
+ c. encode ( buf) ;
146
+ }
147
+ std:: path:: Prefix :: VerbatimUNC ( server, share) => {
148
+ VERBATIM . encode ( buf) ;
149
+ UNC . encode ( buf) ;
150
+ SEP . encode ( buf) ;
151
+ server. encode ( buf) ;
152
+ SEP . encode ( buf) ;
153
+ share. encode ( buf) ;
154
+ }
155
+ std:: path:: Prefix :: VerbatimDisk ( d) => {
156
+ VERBATIM . encode ( buf) ;
157
+ d. encode ( buf) ;
158
+ COLON . encode ( buf) ;
159
+ }
160
+ std:: path:: Prefix :: DeviceNS ( device) => {
161
+ DEVICE . encode ( buf) ;
162
+ device. encode ( buf) ;
163
+ }
164
+ std:: path:: Prefix :: UNC ( server, share) => {
165
+ SEP . encode ( buf) ;
166
+ SEP . encode ( buf) ;
167
+ server. encode ( buf) ;
168
+ SEP . encode ( buf) ;
169
+ share. encode ( buf) ;
170
+ }
171
+ std:: path:: Prefix :: Disk ( d) => {
172
+ d. encode ( buf) ;
173
+ COLON . encode ( buf) ;
174
+ }
175
+ }
176
+ }
177
+ }
178
+ #[ test]
179
+ fn paths_encoding ( ) {
180
+ // drive letter casing agnostic
181
+ test_eq ( "C:/x.rs" , "c:/x.rs" ) ;
182
+ // separator agnostic
183
+ test_eq ( "C:/x/y.rs" , "C:\\ x\\ y.rs" ) ;
184
+
185
+ fn test_eq ( a : & str , b : & str ) {
186
+ let mut b1 = Vec :: new ( ) ;
187
+ let mut b2 = Vec :: new ( ) ;
188
+ vfs ( a) . encode ( & mut b1) ;
189
+ vfs ( b) . encode ( & mut b2) ;
190
+ assert_eq ! ( b1, b2) ;
191
+ }
192
+ }
193
+
194
+ #[ test]
195
+ fn test_sep_root_dir_encoding ( ) {
196
+ let mut buf = Vec :: new ( ) ;
197
+ vfs ( "C:/x/y" ) . encode ( & mut buf) ;
198
+ assert_eq ! ( & buf, & [ 0 , 67 , 0 , 58 , 0 , 92 , 0 , 120 , 0 , 92 , 0 , 121 , 0 ] )
199
+ }
200
+
201
+ #[ cfg( test) ]
202
+ fn vfs ( str : & str ) -> super :: VfsPath {
203
+ use super :: { AbsPathBuf , VfsPath } ;
204
+ use std:: convert:: TryFrom ;
205
+ VfsPath :: from ( AbsPathBuf :: try_from ( str) . unwrap ( ) )
206
+ }
207
+ }
208
+
84
209
#[ derive( Clone , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
85
210
enum VfsPathRepr {
86
211
PathBuf ( AbsPathBuf ) ,
0 commit comments