This allows a stable/non-changing buffer to be used.
Unified · Split
| @@ -3,7 +3,7 @@ use std::collections::BTreeSet; · 2 unmodified lines | |||
| 3 | use git_hash::ObjectId; | 3 | use git_hash::ObjectId; |
| 4 | 4 | ||
| 5 | use crate::{ | 5 | use crate::{ |
| 6 | peel, | 6 | packed, peel, |
| 7 | raw::Reference, | 7 | raw::Reference, |
| 8 | store_impl::{file, file::log}, | 8 | store_impl::{file, file::log}, |
| 9 | Target, | 9 | Target, |
| @@ -27,11 +27,28 @@ pub trait ReferenceExt: Sealed { · 17 unmodified lines | |||
| 27 | find: impl FnMut(git_hash::ObjectId, &mut Vec<u8>) -> Result<Option<(git_object::Kind, &[u8])>, E>, | 27 | find: impl FnMut(git_hash::ObjectId, &mut Vec<u8>) -> Result<Option<(git_object::Kind, &[u8])>, E>, |
| 28 | ) -> Result<ObjectId, peel::to_id::Error>; | 28 | ) -> Result<ObjectId, peel::to_id::Error>; |
| 29 | 29 | ||
| 30 | /// For details, see [Reference::peel_to_id_in_place()], with support for a known stable packed buffer. | ||
| 31 | fn peel_to_id_in_place_packed<E: std::error::Error + Send + Sync + 'static>( | ||
| 32 | &mut self, | ||
| 33 | store: &file::Store, | ||
| 34 | find: impl FnMut(git_hash::ObjectId, &mut Vec<u8>) -> Result<Option<(git_object::Kind, &[u8])>, E>, | ||
| 35 | packed: Option<&packed::Buffer>, | ||
| 36 | ) -> Result<ObjectId, peel::to_id::Error>; | ||
| 37 | |||
| 38 | /// Follow this symbolic reference one level and return the ref it refers to. | ||
| 39 | /// | ||
| 40 | /// Returns `None` if this is not a symbolic reference, hence the leaf of the chain. | ||
| 41 | fn follow(&self, store: &file::Store) -> Option<Result<Reference, file::find::existing::Error>>; | ||
| 42 | |||
| 30 | /// Follow this symbolic reference one level and return the ref it refers to, | 43 | /// Follow this symbolic reference one level and return the ref it refers to, |
| 31 | /// possibly providing access to `packed` references for lookup if it contains the referent. | 44 | /// possibly providing access to `packed` references for lookup if it contains the referent. |
| 32 | /// | 45 | /// |
| 33 | /// Returns `None` if this is not a symbolic reference, hence the leaf of the chain. | 46 | /// Returns `None` if this is not a symbolic reference, hence the leaf of the chain. |
| 34 | fn follow(&self, store: &file::Store) -> Option<Result<Reference, file::find::existing::Error>>; | 47 | fn follow_packed( |
| 48 | &self, | ||
| 49 | store: &file::Store, | ||
| 50 | packed: Option<&packed::Buffer>, | ||
| 51 | ) -> Option<Result<Reference, file::find::existing::Error>>; | ||
| 35 | } | 52 | } |
| 36 | 53 | ||
| 37 | impl ReferenceExt for Reference { | 54 | impl ReferenceExt for Reference { |
| @@ -50,9 +67,21 @@ impl ReferenceExt for Reference { · 12 unmodified lines | |||
| 50 | } | 67 | } |
| 51 | 68 | ||
| 52 | fn peel_to_id_in_place<E: std::error::Error + Send + Sync + 'static>( | 69 | fn peel_to_id_in_place<E: std::error::Error + Send + Sync + 'static>( |
| 70 | &mut self, | ||
| 71 | store: &file::Store, | ||
| 72 | find: impl FnMut(git_hash::ObjectId, &mut Vec<u8>) -> Result<Option<(git_object::Kind, &[u8])>, E>, | ||
| 73 | ) -> Result<ObjectId, peel::to_id::Error> { | ||
| 74 | let packed = store.assure_packed_refs_uptodate().map_err(|err| { | ||
| 75 | peel::to_id::Error::Follow(file::find::existing::Error::Find(file::find::Error::PackedOpen(err))) | ||
| 76 | })?; | ||
| 77 | self.peel_to_id_in_place_packed(store, find, packed.as_deref()) | ||
| 78 | } | ||
| 79 | |||
| 80 | fn peel_to_id_in_place_packed<E: std::error::Error + Send + Sync + 'static>( | ||
| 53 | &mut self, | 81 | &mut self, |
| 54 | store: &file::Store, | 82 | store: &file::Store, |
| 55 | mut find: impl FnMut(git_hash::ObjectId, &mut Vec<u8>) -> Result<Option<(git_object::Kind, &[u8])>, E>, | 83 | mut find: impl FnMut(git_hash::ObjectId, &mut Vec<u8>) -> Result<Option<(git_object::Kind, &[u8])>, E>, |
| 84 | packed: Option<&packed::Buffer>, | ||
| 56 | ) -> Result<ObjectId, peel::to_id::Error> { | 85 | ) -> Result<ObjectId, peel::to_id::Error> { |
| 57 | match self.peeled { | 86 | match self.peeled { |
| 58 | Some(peeled) => { | 87 | Some(peeled) => { |
| @@ -63,7 +92,7 @@ impl ReferenceExt for Reference { · 4 unmodified lines | |||
| 63 | if self.target.kind() == crate::Kind::Symbolic { | 92 | if self.target.kind() == crate::Kind::Symbolic { |
| 64 | let mut seen = BTreeSet::new(); | 93 | let mut seen = BTreeSet::new(); |
| 65 | let cursor = &mut *self; | 94 | let cursor = &mut *self; |
| 66 | while let Some(next) = cursor.follow(store) { | 95 | while let Some(next) = cursor.follow_packed(store, packed) { |
| 67 | let next = next?; | 96 | let next = next?; |
| 68 | if seen.contains(&next.name) { | 97 | if seen.contains(&next.name) { |
| 69 | return Err(peel::to_id::Error::Cycle(store.base.join(cursor.name.to_path()))); | 98 | return Err(peel::to_id::Error::Cycle(store.base.join(cursor.name.to_path()))); |
| @@ -107,6 +136,21 @@ impl ReferenceExt for Reference { · 37 unmodified lines | |||
| 107 | } | 136 | } |
| 108 | 137 | ||
| 109 | fn follow(&self, store: &file::Store) -> Option<Result<Reference, file::find::existing::Error>> { | 138 | fn follow(&self, store: &file::Store) -> Option<Result<Reference, file::find::existing::Error>> { |
| 139 | let packed = match store | ||
| 140 | .assure_packed_refs_uptodate() | ||
| 141 | .map_err(|err| file::find::existing::Error::Find(file::find::Error::PackedOpen(err))) | ||
| 142 | { | ||
| 143 | Ok(packed) => packed, | ||
| 144 | Err(err) => return Some(Err(err)), | ||
| 145 | }; | ||
| 146 | self.follow_packed(store, packed.as_deref()) | ||
| 147 | } | ||
| 148 | |||
| 149 | fn follow_packed( | ||
| 150 | &self, | ||
| 151 | store: &file::Store, | ||
| 152 | packed: Option<&packed::Buffer>, | ||
| 153 | ) -> Option<Result<Reference, file::find::existing::Error>> { | ||
| 110 | match self.peeled { | 154 | match self.peeled { |
| 111 | Some(peeled) => Some(Ok(Reference { | 155 | Some(peeled) => Some(Ok(Reference { |
| 112 | name: self.name.clone(), | 156 | name: self.name.clone(), |
| @@ -115,21 +159,13 @@ impl ReferenceExt for Reference { · 2 unmodified lines | |||
| 115 | })), | 159 | })), |
| 116 | None => match &self.target { | 160 | None => match &self.target { |
| 117 | Target::Peeled(_) => None, | 161 | Target::Peeled(_) => None, |
| 118 | Target::Symbolic(full_name) => { | 162 | Target::Symbolic(full_name) => match store.try_find_packed(full_name.to_partial(), packed) { |
| 119 | let path = full_name.to_path(); | 163 | Ok(Some(next)) => Some(Ok(next)), |
| 120 | let packed = match store | 164 | Ok(None) => Some(Err(file::find::existing::Error::NotFound( |
| 121 | .assure_packed_refs_uptodate() | 165 | full_name.to_path().into_owned(), |
| 122 | .map_err(|err| file::find::existing::Error::Find(file::find::Error::PackedOpen(err))) | 166 | ))), |
| 123 | { | 167 | Err(err) => Some(Err(file::find::existing::Error::Find(err))), |
| 124 | Ok(packed) => packed, | 168 | }, |
| 125 | Err(err) => return Some(Err(err)), | ||
| 126 | }; | ||
| 127 | match store.find_one_with_verified_input(path.as_ref(), packed.as_deref()) { | ||
| 128 | Ok(Some(next)) => Some(Ok(next)), | ||
| 129 | Ok(None) => Some(Err(file::find::existing::Error::NotFound(path.into_owned()))), | ||
| 130 | Err(err) => Some(Err(file::find::existing::Error::Find(err))), | ||
| 131 | } | ||
| 132 | } | ||
| 133 | }, | 169 | }, |
| 134 | } | 170 | } |
| 135 | } | 171 | } |