@@ -46,15 +46,16 @@ impl<'a> Editor<'a> {
46
46
find,
47
47
object_hash,
48
48
trees : HashMap :: from_iter ( Some ( ( empty_path ( ) , root) ) ) ,
49
- path_buf : Vec :: with_capacity ( 256 ) . into ( ) ,
49
+ path_buf : BString :: from ( Vec :: with_capacity ( 256 ) ) . into ( ) ,
50
50
tree_buf : Vec :: with_capacity ( 512 ) ,
51
51
}
52
52
}
53
53
}
54
54
55
55
/// Operations
56
56
impl Editor < ' _ > {
57
- /// Write the entire in-memory state of all changed trees (and only changed trees) to `out`.
57
+ /// Write the entire in-memory state of all changed trees (and only changed trees) to `out`, and remove
58
+ /// written portions from our state except for the root tree, which affects [`get()`](Editor::get()).
58
59
/// Note that the returned object id *can* be the empty tree if everything was removed or if nothing
59
60
/// was added to the tree.
60
61
///
@@ -72,7 +73,7 @@ impl Editor<'_> {
72
73
/// It is absolutely and intentionally possible to write out invalid trees with this method.
73
74
/// Higher layers are expected to perform detailed validation.
74
75
pub fn write < E > ( & mut self , out : impl FnMut ( & Tree ) -> Result < ObjectId , E > ) -> Result < ObjectId , E > {
75
- self . path_buf . clear ( ) ;
76
+ self . path_buf . borrow_mut ( ) . clear ( ) ;
76
77
self . write_at_pathbuf ( out, WriteMode :: Normal )
77
78
}
78
79
@@ -85,10 +86,24 @@ impl Editor<'_> {
85
86
I : IntoIterator < Item = C > ,
86
87
C : AsRef < BStr > ,
87
88
{
88
- self . path_buf . clear ( ) ;
89
+ self . path_buf . borrow_mut ( ) . clear ( ) ;
89
90
self . upsert_or_remove_at_pathbuf ( rela_path, None )
90
91
}
91
92
93
+ /// Obtain the entry at `rela_path` or return `None` if none was found, or the tree wasn't yet written
94
+ /// to that point.
95
+ /// Note that after [writing](Self::write) only the root path remains, all other intermediate trees are removed.
96
+ /// The entry can be anything that can be stored in a tree, but may have a null-id if it's a newly
97
+ /// inserted tree. Also, ids of trees might not be accurate as they may have been changed in memory.
98
+ pub fn get < I , C > ( & self , rela_path : I ) -> Option < & tree:: Entry >
99
+ where
100
+ I : IntoIterator < Item = C > ,
101
+ C : AsRef < BStr > ,
102
+ {
103
+ self . path_buf . borrow_mut ( ) . clear ( ) ;
104
+ self . get_inner ( rela_path)
105
+ }
106
+
92
107
/// Insert a new entry of `kind` with `id` at `rela_path`, an iterator over each path component in the tree,
93
108
/// like `a/b/c`. Names are matched case-sensitively.
94
109
///
@@ -108,10 +123,41 @@ impl Editor<'_> {
108
123
I : IntoIterator < Item = C > ,
109
124
C : AsRef < BStr > ,
110
125
{
111
- self . path_buf . clear ( ) ;
126
+ self . path_buf . borrow_mut ( ) . clear ( ) ;
112
127
self . upsert_or_remove_at_pathbuf ( rela_path, Some ( ( kind, id, UpsertMode :: Normal ) ) )
113
128
}
114
129
130
+ fn get_inner < I , C > ( & self , rela_path : I ) -> Option < & tree:: Entry >
131
+ where
132
+ I : IntoIterator < Item = C > ,
133
+ C : AsRef < BStr > ,
134
+ {
135
+ let mut path_buf = self . path_buf . borrow_mut ( ) ;
136
+ let mut cursor = self . trees . get ( path_buf. as_bstr ( ) ) . expect ( "root is always present" ) ;
137
+ let mut rela_path = rela_path. into_iter ( ) . peekable ( ) ;
138
+ while let Some ( name) = rela_path. next ( ) {
139
+ let name = name. as_ref ( ) ;
140
+ let is_last = rela_path. peek ( ) . is_none ( ) ;
141
+ match cursor
142
+ . entries
143
+ . binary_search_by ( |e| cmp_entry_with_name ( e, name, true ) )
144
+ . or_else ( |_| cursor. entries . binary_search_by ( |e| cmp_entry_with_name ( e, name, false ) ) )
145
+ {
146
+ Ok ( idx) if is_last => return Some ( & cursor. entries [ idx] ) ,
147
+ Ok ( idx) => {
148
+ if cursor. entries [ idx] . mode . is_tree ( ) {
149
+ push_path_component ( & mut path_buf, name) ;
150
+ cursor = self . trees . get ( path_buf. as_bstr ( ) ) ?;
151
+ } else {
152
+ break ;
153
+ }
154
+ }
155
+ Err ( _) => break ,
156
+ } ;
157
+ }
158
+ None
159
+ }
160
+
115
161
fn write_at_pathbuf < E > (
116
162
& mut self ,
117
163
mut out : impl FnMut ( & Tree ) -> Result < ObjectId , E > ,
@@ -120,11 +166,12 @@ impl Editor<'_> {
120
166
assert_ne ! ( self . trees. len( ) , 0 , "there is at least the root tree" ) ;
121
167
122
168
// back is for children, front is for parents.
169
+ let path_buf = self . path_buf . borrow_mut ( ) ;
123
170
let mut parents = vec ! [ (
124
171
None :: <usize >,
125
- self . path_buf. clone( ) ,
172
+ path_buf. clone( ) ,
126
173
self . trees
127
- . remove( & path_hash ( & self . path_buf) )
174
+ . remove( path_buf. as_bstr ( ) )
128
175
. expect( "root tree is always present" ) ,
129
176
) ] ;
130
177
let mut children = Vec :: new ( ) ;
@@ -133,7 +180,7 @@ impl Editor<'_> {
133
180
for entry in & tree. entries {
134
181
if entry. mode . is_tree ( ) {
135
182
let prev_len = push_path_component ( & mut rela_path, & entry. filename ) ;
136
- if let Some ( sub_tree) = self . trees . remove ( & path_hash ( & rela_path) ) {
183
+ if let Some ( sub_tree) = self . trees . remove ( & rela_path) {
137
184
all_entries_unchanged_or_written = false ;
138
185
let next_parent_idx = parents. len ( ) ;
139
186
children. push ( ( Some ( next_parent_idx) , rela_path. clone ( ) , sub_tree) ) ;
@@ -167,7 +214,7 @@ impl Editor<'_> {
167
214
}
168
215
} else if parents. is_empty ( ) {
169
216
debug_assert ! ( children. is_empty( ) , "we consume children before parents" ) ;
170
- debug_assert_eq ! ( rela_path, self . path_buf, "this should always be the root tree" ) ;
217
+ debug_assert_eq ! ( rela_path, * * path_buf, "this should always be the root tree" ) ;
171
218
172
219
// There may be left-over trees if they are replaced with blobs for example.
173
220
match out ( & tree) {
@@ -207,10 +254,8 @@ impl Editor<'_> {
207
254
I : IntoIterator < Item = C > ,
208
255
C : AsRef < BStr > ,
209
256
{
210
- let mut cursor = self
211
- . trees
212
- . get_mut ( & path_hash ( & self . path_buf ) )
213
- . expect ( "root is always present" ) ;
257
+ let mut path_buf = self . path_buf . borrow_mut ( ) ;
258
+ let mut cursor = self . trees . get_mut ( path_buf. as_bstr ( ) ) . expect ( "root is always present" ) ;
214
259
let mut rela_path = rela_path. into_iter ( ) . peekable ( ) ;
215
260
let new_kind_is_tree = kind_and_id. map_or ( false , |( kind, _, _) | kind == EntryKind :: Tree ) ;
216
261
while let Some ( name) = rela_path. next ( ) {
@@ -294,9 +339,8 @@ impl Editor<'_> {
294
339
if is_last && kind_and_id. map_or ( false , |( _, _, mode) | mode == UpsertMode :: Normal ) {
295
340
break ;
296
341
}
297
- push_path_component ( & mut self . path_buf , name) ;
298
- let path_id = path_hash ( & self . path_buf ) ;
299
- cursor = match self . trees . entry ( path_id) {
342
+ push_path_component ( & mut path_buf, name) ;
343
+ cursor = match self . trees . entry ( path_buf. clone ( ) ) {
300
344
hash_map:: Entry :: Occupied ( e) => e. into_mut ( ) ,
301
345
hash_map:: Entry :: Vacant ( e) => e. insert (
302
346
if let Some ( tree_id) = tree_to_lookup. filter ( |tree_id| !tree_id. is_empty_tree ( ) ) {
@@ -307,6 +351,7 @@ impl Editor<'_> {
307
351
) ,
308
352
} ;
309
353
}
354
+ drop ( path_buf) ;
310
355
Ok ( self )
311
356
}
312
357
@@ -325,7 +370,7 @@ impl Editor<'_> {
325
370
mod cursor {
326
371
use crate :: tree:: editor:: { Cursor , UpsertMode , WriteMode } ;
327
372
use crate :: tree:: { Editor , EntryKind } ;
328
- use crate :: Tree ;
373
+ use crate :: { tree , Tree } ;
329
374
use bstr:: { BStr , BString } ;
330
375
use gix_hash:: ObjectId ;
331
376
@@ -350,26 +395,41 @@ mod cursor {
350
395
I : IntoIterator < Item = C > ,
351
396
C : AsRef < BStr > ,
352
397
{
353
- self . path_buf . clear ( ) ;
398
+ self . path_buf . borrow_mut ( ) . clear ( ) ;
354
399
self . upsert_or_remove_at_pathbuf (
355
400
rela_path,
356
401
Some ( ( EntryKind :: Tree , self . object_hash . null ( ) , UpsertMode :: AssureTreeOnly ) ) ,
357
402
) ?;
403
+ let prefix = self . path_buf . borrow_mut ( ) . clone ( ) ;
358
404
Ok ( Cursor {
359
- prefix : self . path_buf . clone ( ) , /* set during the upsert call */
405
+ prefix, /* set during the upsert call */
360
406
parent : self ,
361
407
} )
362
408
}
363
409
}
364
410
365
411
impl Cursor < ' _ , ' _ > {
412
+ /// Obtain the entry at `rela_path` or return `None` if none was found, or the tree wasn't yet written
413
+ /// to that point.
414
+ /// Note that after [writing](Self::write) only the root path remains, all other intermediate trees are removed.
415
+ /// The entry can be anything that can be stored in a tree, but may have a null-id if it's a newly
416
+ /// inserted tree. Also, ids of trees might not be accurate as they may have been changed in memory.
417
+ pub fn get < I , C > ( & self , rela_path : I ) -> Option < & tree:: Entry >
418
+ where
419
+ I : IntoIterator < Item = C > ,
420
+ C : AsRef < BStr > ,
421
+ {
422
+ self . parent . path_buf . borrow_mut ( ) . clone_from ( & self . prefix ) ;
423
+ self . parent . get_inner ( rela_path)
424
+ }
425
+
366
426
/// Like [`Editor::upsert()`], but with the constraint of only editing in this cursor's tree.
367
427
pub fn upsert < I , C > ( & mut self , rela_path : I , kind : EntryKind , id : ObjectId ) -> Result < & mut Self , super :: Error >
368
428
where
369
429
I : IntoIterator < Item = C > ,
370
430
C : AsRef < BStr > ,
371
431
{
372
- self . parent . path_buf . clone_from ( & self . prefix ) ;
432
+ self . parent . path_buf . borrow_mut ( ) . clone_from ( & self . prefix ) ;
373
433
self . parent
374
434
. upsert_or_remove_at_pathbuf ( rela_path, Some ( ( kind, id, UpsertMode :: Normal ) ) ) ?;
375
435
Ok ( self )
@@ -381,14 +441,14 @@ mod cursor {
381
441
I : IntoIterator < Item = C > ,
382
442
C : AsRef < BStr > ,
383
443
{
384
- self . parent . path_buf . clone_from ( & self . prefix ) ;
444
+ self . parent . path_buf . borrow_mut ( ) . clone_from ( & self . prefix ) ;
385
445
self . parent . upsert_or_remove_at_pathbuf ( rela_path, None ) ?;
386
446
Ok ( self )
387
447
}
388
448
389
449
/// Like [`Editor::write()`], but will write only the subtree of the cursor.
390
450
pub fn write < E > ( & mut self , out : impl FnMut ( & Tree ) -> Result < ObjectId , E > ) -> Result < ObjectId , E > {
391
- self . parent . path_buf . clone_from ( & self . prefix ) ;
451
+ self . parent . path_buf . borrow_mut ( ) . clone_from ( & self . prefix ) ;
392
452
self . parent . write_at_pathbuf ( out, WriteMode :: FromCursor )
393
453
}
394
454
}
@@ -424,10 +484,6 @@ fn empty_path() -> BString {
424
484
BString :: default ( )
425
485
}
426
486
427
- fn path_hash ( path : & [ u8 ] ) -> BString {
428
- path. to_vec ( ) . into ( )
429
- }
430
-
431
487
fn push_path_component ( base : & mut BString , component : & [ u8 ] ) -> usize {
432
488
let prev_len = base. len ( ) ;
433
489
debug_assert ! ( base. last( ) != Some ( & b'/' ) ) ;
0 commit comments