@@ -91,12 +91,21 @@ impl nohash_hasher::IsEnabled for FileId {}
91
91
pub struct Vfs {
92
92
interner : PathInterner ,
93
93
data : Vec < FileState > ,
94
+ // FIXME: This should be a HashMap<FileId, ChangeFile>
95
+ // right now we do a nasty deduplication in GlobalState::process_changes that would be a lot
96
+ // easier to handle here on insertion.
94
97
changes : Vec < ChangedFile > ,
98
+ // The above FIXME would then also get rid of this probably
99
+ created_this_cycle : Vec < FileId > ,
95
100
}
96
101
97
- #[ derive( Copy , PartialEq , PartialOrd , Clone ) ]
102
+ #[ derive( Copy , Clone , Debug , PartialEq , PartialOrd ) ]
98
103
pub enum FileState {
104
+ /// The file has been created this cycle.
105
+ Created ,
106
+ /// The file exists.
99
107
Exists ,
108
+ /// The file is deleted.
100
109
Deleted ,
101
110
}
102
111
@@ -121,6 +130,11 @@ impl ChangedFile {
121
130
matches ! ( self . change, Change :: Create ( _) | Change :: Delete )
122
131
}
123
132
133
+ /// Returns `true` if the change is [`Create`](ChangeKind::Create).
134
+ pub fn is_created ( & self ) -> bool {
135
+ matches ! ( self . change, Change :: Create ( _) )
136
+ }
137
+
124
138
/// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
125
139
pub fn is_modified ( & self ) -> bool {
126
140
matches ! ( self . change, Change :: Modify ( _) )
@@ -160,7 +174,9 @@ pub enum ChangeKind {
160
174
impl Vfs {
161
175
/// Id of the given path if it exists in the `Vfs` and is not deleted.
162
176
pub fn file_id ( & self , path : & VfsPath ) -> Option < FileId > {
163
- self . interner . get ( path) . filter ( |& it| matches ! ( self . get( it) , FileState :: Exists ) )
177
+ self . interner
178
+ . get ( path)
179
+ . filter ( |& it| matches ! ( self . get( it) , FileState :: Exists | FileState :: Created ) )
164
180
}
165
181
166
182
/// File path corresponding to the given `file_id`.
@@ -178,7 +194,9 @@ impl Vfs {
178
194
pub fn iter ( & self ) -> impl Iterator < Item = ( FileId , & VfsPath ) > + ' _ {
179
195
( 0 ..self . data . len ( ) )
180
196
. map ( |it| FileId ( it as u32 ) )
181
- . filter ( move |& file_id| matches ! ( self . get( file_id) , FileState :: Exists ) )
197
+ . filter ( move |& file_id| {
198
+ matches ! ( self . get( file_id) , FileState :: Exists | FileState :: Created )
199
+ } )
182
200
. map ( move |file_id| {
183
201
let path = self . interner . lookup ( file_id) ;
184
202
( file_id, path)
@@ -193,27 +211,43 @@ impl Vfs {
193
211
/// [`FileId`] for it.
194
212
pub fn set_file_contents ( & mut self , path : VfsPath , contents : Option < Vec < u8 > > ) -> bool {
195
213
let file_id = self . alloc_file_id ( path) ;
196
- let change_kind = match ( self . get ( file_id) , contents) {
214
+ let state = self . get ( file_id) ;
215
+ let change_kind = match ( state, contents) {
197
216
( FileState :: Deleted , None ) => return false ,
198
217
( FileState :: Deleted , Some ( v) ) => Change :: Create ( v) ,
199
- ( FileState :: Exists , None ) => Change :: Delete ,
200
- ( FileState :: Exists , Some ( v) ) => Change :: Modify ( v) ,
218
+ ( FileState :: Exists | FileState :: Created , None ) => Change :: Delete ,
219
+ ( FileState :: Exists | FileState :: Created , Some ( v) ) => Change :: Modify ( v) ,
220
+ } ;
221
+ self . data [ file_id. 0 as usize ] = match change_kind {
222
+ Change :: Create ( _) => {
223
+ self . created_this_cycle . push ( file_id) ;
224
+ FileState :: Created
225
+ }
226
+ // If the file got created this cycle, make sure we keep it that way even
227
+ // if a modify comes in
228
+ Change :: Modify ( _) if matches ! ( state, FileState :: Created ) => FileState :: Created ,
229
+ Change :: Modify ( _) => FileState :: Exists ,
230
+ Change :: Delete => FileState :: Deleted ,
201
231
} ;
202
232
let changed_file = ChangedFile { file_id, change : change_kind } ;
203
- self . data [ file_id. 0 as usize ] =
204
- if changed_file. exists ( ) { FileState :: Exists } else { FileState :: Deleted } ;
205
233
self . changes . push ( changed_file) ;
206
234
true
207
235
}
208
236
209
237
/// Drain and returns all the changes in the `Vfs`.
210
238
pub fn take_changes ( & mut self ) -> Vec < ChangedFile > {
239
+ for file_id in self . created_this_cycle . drain ( ..) {
240
+ if self . data [ file_id. 0 as usize ] == FileState :: Created {
241
+ // downgrade the file from `Created` to `Exists` as the cycle is done
242
+ self . data [ file_id. 0 as usize ] = FileState :: Exists ;
243
+ }
244
+ }
211
245
mem:: take ( & mut self . changes )
212
246
}
213
247
214
248
/// Provides a panic-less way to verify file_id validity.
215
249
pub fn exists ( & self , file_id : FileId ) -> bool {
216
- matches ! ( self . get( file_id) , FileState :: Exists )
250
+ matches ! ( self . get( file_id) , FileState :: Exists | FileState :: Created )
217
251
}
218
252
219
253
/// Returns the id associated with `path`
0 commit comments