@@ -46,15 +46,16 @@ impl<'a> Editor<'a> {
4646 find,
4747 object_hash,
4848 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 ( ) ,
5050 tree_buf : Vec :: with_capacity ( 512 ) ,
5151 }
5252 }
5353}
5454
5555/// Operations
5656impl 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()).
5859 /// Note that the returned object id *can* be the empty tree if everything was removed or if nothing
5960 /// was added to the tree.
6061 ///
@@ -72,7 +73,7 @@ impl Editor<'_> {
7273 /// It is absolutely and intentionally possible to write out invalid trees with this method.
7374 /// Higher layers are expected to perform detailed validation.
7475 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 ( ) ;
7677 self . write_at_pathbuf ( out, WriteMode :: Normal )
7778 }
7879
@@ -85,10 +86,24 @@ impl Editor<'_> {
8586 I : IntoIterator < Item = C > ,
8687 C : AsRef < BStr > ,
8788 {
88- self . path_buf . clear ( ) ;
89+ self . path_buf . borrow_mut ( ) . clear ( ) ;
8990 self . upsert_or_remove_at_pathbuf ( rela_path, None )
9091 }
9192
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+
92107 /// Insert a new entry of `kind` with `id` at `rela_path`, an iterator over each path component in the tree,
93108 /// like `a/b/c`. Names are matched case-sensitively.
94109 ///
@@ -108,10 +123,41 @@ impl Editor<'_> {
108123 I : IntoIterator < Item = C > ,
109124 C : AsRef < BStr > ,
110125 {
111- self . path_buf . clear ( ) ;
126+ self . path_buf . borrow_mut ( ) . clear ( ) ;
112127 self . upsert_or_remove_at_pathbuf ( rela_path, Some ( ( kind, id, UpsertMode :: Normal ) ) )
113128 }
114129
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+
115161 fn write_at_pathbuf < E > (
116162 & mut self ,
117163 mut out : impl FnMut ( & Tree ) -> Result < ObjectId , E > ,
@@ -120,11 +166,12 @@ impl Editor<'_> {
120166 assert_ne ! ( self . trees. len( ) , 0 , "there is at least the root tree" ) ;
121167
122168 // back is for children, front is for parents.
169+ let path_buf = self . path_buf . borrow_mut ( ) ;
123170 let mut parents = vec ! [ (
124171 None :: <usize >,
125- self . path_buf. clone( ) ,
172+ path_buf. clone( ) ,
126173 self . trees
127- . remove( & path_hash ( & self . path_buf) )
174+ . remove( path_buf. as_bstr ( ) )
128175 . expect( "root tree is always present" ) ,
129176 ) ] ;
130177 let mut children = Vec :: new ( ) ;
@@ -133,7 +180,7 @@ impl Editor<'_> {
133180 for entry in & tree. entries {
134181 if entry. mode . is_tree ( ) {
135182 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) {
137184 all_entries_unchanged_or_written = false ;
138185 let next_parent_idx = parents. len ( ) ;
139186 children. push ( ( Some ( next_parent_idx) , rela_path. clone ( ) , sub_tree) ) ;
@@ -167,7 +214,7 @@ impl Editor<'_> {
167214 }
168215 } else if parents. is_empty ( ) {
169216 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" ) ;
171218
172219 // There may be left-over trees if they are replaced with blobs for example.
173220 match out ( & tree) {
@@ -207,10 +254,8 @@ impl Editor<'_> {
207254 I : IntoIterator < Item = C > ,
208255 C : AsRef < BStr > ,
209256 {
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" ) ;
214259 let mut rela_path = rela_path. into_iter ( ) . peekable ( ) ;
215260 let new_kind_is_tree = kind_and_id. map_or ( false , |( kind, _, _) | kind == EntryKind :: Tree ) ;
216261 while let Some ( name) = rela_path. next ( ) {
@@ -294,9 +339,8 @@ impl Editor<'_> {
294339 if is_last && kind_and_id. map_or ( false , |( _, _, mode) | mode == UpsertMode :: Normal ) {
295340 break ;
296341 }
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 ( ) ) {
300344 hash_map:: Entry :: Occupied ( e) => e. into_mut ( ) ,
301345 hash_map:: Entry :: Vacant ( e) => e. insert (
302346 if let Some ( tree_id) = tree_to_lookup. filter ( |tree_id| !tree_id. is_empty_tree ( ) ) {
@@ -307,6 +351,7 @@ impl Editor<'_> {
307351 ) ,
308352 } ;
309353 }
354+ drop ( path_buf) ;
310355 Ok ( self )
311356 }
312357
@@ -325,7 +370,7 @@ impl Editor<'_> {
325370mod cursor {
326371 use crate :: tree:: editor:: { Cursor , UpsertMode , WriteMode } ;
327372 use crate :: tree:: { Editor , EntryKind } ;
328- use crate :: Tree ;
373+ use crate :: { tree , Tree } ;
329374 use bstr:: { BStr , BString } ;
330375 use gix_hash:: ObjectId ;
331376
@@ -350,26 +395,41 @@ mod cursor {
350395 I : IntoIterator < Item = C > ,
351396 C : AsRef < BStr > ,
352397 {
353- self . path_buf . clear ( ) ;
398+ self . path_buf . borrow_mut ( ) . clear ( ) ;
354399 self . upsert_or_remove_at_pathbuf (
355400 rela_path,
356401 Some ( ( EntryKind :: Tree , self . object_hash . null ( ) , UpsertMode :: AssureTreeOnly ) ) ,
357402 ) ?;
403+ let prefix = self . path_buf . borrow_mut ( ) . clone ( ) ;
358404 Ok ( Cursor {
359- prefix : self . path_buf . clone ( ) , /* set during the upsert call */
405+ prefix, /* set during the upsert call */
360406 parent : self ,
361407 } )
362408 }
363409 }
364410
365411 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+
366426 /// Like [`Editor::upsert()`], but with the constraint of only editing in this cursor's tree.
367427 pub fn upsert < I , C > ( & mut self , rela_path : I , kind : EntryKind , id : ObjectId ) -> Result < & mut Self , super :: Error >
368428 where
369429 I : IntoIterator < Item = C > ,
370430 C : AsRef < BStr > ,
371431 {
372- self . parent . path_buf . clone_from ( & self . prefix ) ;
432+ self . parent . path_buf . borrow_mut ( ) . clone_from ( & self . prefix ) ;
373433 self . parent
374434 . upsert_or_remove_at_pathbuf ( rela_path, Some ( ( kind, id, UpsertMode :: Normal ) ) ) ?;
375435 Ok ( self )
@@ -381,14 +441,14 @@ mod cursor {
381441 I : IntoIterator < Item = C > ,
382442 C : AsRef < BStr > ,
383443 {
384- self . parent . path_buf . clone_from ( & self . prefix ) ;
444+ self . parent . path_buf . borrow_mut ( ) . clone_from ( & self . prefix ) ;
385445 self . parent . upsert_or_remove_at_pathbuf ( rela_path, None ) ?;
386446 Ok ( self )
387447 }
388448
389449 /// Like [`Editor::write()`], but will write only the subtree of the cursor.
390450 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 ) ;
392452 self . parent . write_at_pathbuf ( out, WriteMode :: FromCursor )
393453 }
394454 }
@@ -424,10 +484,6 @@ fn empty_path() -> BString {
424484 BString :: default ( )
425485}
426486
427- fn path_hash ( path : & [ u8 ] ) -> BString {
428- path. to_vec ( ) . into ( )
429- }
430-
431487fn push_path_component ( base : & mut BString , component : & [ u8 ] ) -> usize {
432488 let prev_len = base. len ( ) ;
433489 debug_assert ! ( base. last( ) != Some ( & b'/' ) ) ;
0 commit comments