@@ -56,6 +56,8 @@ pub use crate::{
56
56
} ;
57
57
pub use paths:: { AbsPath , AbsPathBuf } ;
58
58
59
+ use rustc_hash:: FxHasher ;
60
+ use stdx:: hash_once;
59
61
use tracing:: { span, Level } ;
60
62
61
63
/// Handle to a file in [`Vfs`]
@@ -106,7 +108,7 @@ pub enum FileState {
106
108
/// The file has been created this cycle.
107
109
Created ,
108
110
/// The file exists.
109
- Exists ,
111
+ Exists ( u64 ) ,
110
112
/// The file is deleted.
111
113
Deleted ,
112
114
}
@@ -139,13 +141,13 @@ impl ChangedFile {
139
141
140
142
/// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
141
143
pub fn is_modified ( & self ) -> bool {
142
- matches ! ( self . change, Change :: Modify ( _) )
144
+ matches ! ( self . change, Change :: Modify ( _, _ ) )
143
145
}
144
146
145
147
pub fn kind ( & self ) -> ChangeKind {
146
148
match self . change {
147
149
Change :: Create ( _) => ChangeKind :: Create ,
148
- Change :: Modify ( _) => ChangeKind :: Modify ,
150
+ Change :: Modify ( _, _ ) => ChangeKind :: Modify ,
149
151
Change :: Delete => ChangeKind :: Delete ,
150
152
}
151
153
}
@@ -157,7 +159,7 @@ pub enum Change {
157
159
/// The file was (re-)created
158
160
Create ( Vec < u8 > ) ,
159
161
/// The file was modified
160
- Modify ( Vec < u8 > ) ,
162
+ Modify ( Vec < u8 > , u64 ) ,
161
163
/// The file was deleted
162
164
Delete ,
163
165
}
@@ -178,7 +180,7 @@ impl Vfs {
178
180
pub fn file_id ( & self , path : & VfsPath ) -> Option < FileId > {
179
181
self . interner
180
182
. get ( path)
181
- . filter ( |& it| matches ! ( self . get( it) , FileState :: Exists | FileState :: Created ) )
183
+ . filter ( |& it| matches ! ( self . get( it) , FileState :: Exists ( _ ) | FileState :: Created ) )
182
184
}
183
185
184
186
/// File path corresponding to the given `file_id`.
@@ -197,7 +199,7 @@ impl Vfs {
197
199
( 0 ..self . data . len ( ) )
198
200
. map ( |it| FileId ( it as u32 ) )
199
201
. filter ( move |& file_id| {
200
- matches ! ( self . get( file_id) , FileState :: Exists | FileState :: Created )
202
+ matches ! ( self . get( file_id) , FileState :: Exists ( _ ) | FileState :: Created )
201
203
} )
202
204
. map ( move |file_id| {
203
205
let path = self . interner . lookup ( file_id) ;
@@ -218,8 +220,18 @@ impl Vfs {
218
220
let change_kind = match ( state, contents) {
219
221
( FileState :: Deleted , None ) => return false ,
220
222
( FileState :: Deleted , Some ( v) ) => Change :: Create ( v) ,
221
- ( FileState :: Exists | FileState :: Created , None ) => Change :: Delete ,
222
- ( FileState :: Exists | FileState :: Created , Some ( v) ) => Change :: Modify ( v) ,
223
+ ( FileState :: Exists ( _) | FileState :: Created , None ) => Change :: Delete ,
224
+ ( FileState :: Created , Some ( v) ) => {
225
+ let hash = hash_once :: < FxHasher > ( & * v) ;
226
+ Change :: Modify ( v, hash)
227
+ }
228
+ ( FileState :: Exists ( hash) , Some ( v) ) => {
229
+ let new_hash = hash_once :: < FxHasher > ( & * v) ;
230
+ if new_hash == hash {
231
+ return false ;
232
+ }
233
+ Change :: Modify ( v, new_hash)
234
+ }
223
235
} ;
224
236
self . data [ file_id. 0 as usize ] = match change_kind {
225
237
Change :: Create ( _) => {
@@ -228,8 +240,8 @@ impl Vfs {
228
240
}
229
241
// If the file got created this cycle, make sure we keep it that way even
230
242
// if a modify comes in
231
- Change :: Modify ( _) if matches ! ( state, FileState :: Created ) => FileState :: Created ,
232
- Change :: Modify ( _) => FileState :: Exists ,
243
+ Change :: Modify ( _, _ ) if matches ! ( state, FileState :: Created ) => FileState :: Created ,
244
+ Change :: Modify ( _, hash ) => FileState :: Exists ( hash ) ,
233
245
Change :: Delete => FileState :: Deleted ,
234
246
} ;
235
247
let changed_file = ChangedFile { file_id, change : change_kind } ;
@@ -243,15 +255,15 @@ impl Vfs {
243
255
for file_id in self . created_this_cycle . drain ( ..) {
244
256
if self . data [ file_id. 0 as usize ] == FileState :: Created {
245
257
// downgrade the file from `Created` to `Exists` as the cycle is done
246
- self . data [ file_id. 0 as usize ] = FileState :: Exists ;
258
+ self . data [ file_id. 0 as usize ] = FileState :: Exists ( todo ! ( ) ) ;
247
259
}
248
260
}
249
261
mem:: take ( & mut self . changes )
250
262
}
251
263
252
264
/// Provides a panic-less way to verify file_id validity.
253
265
pub fn exists ( & self , file_id : FileId ) -> bool {
254
- matches ! ( self . get( file_id) , FileState :: Exists | FileState :: Created )
266
+ matches ! ( self . get( file_id) , FileState :: Exists ( _ ) | FileState :: Created )
255
267
}
256
268
257
269
/// Returns the id associated with `path`
0 commit comments