History

feat: add Reference::peel_to_id_in_place_packed() and Reference::follow_packed() (#263)

This allows a stable/non-changing buffer to be used.

Sebastian Thiel committed 4 years ago

Commit 03bcac21 parent d3f92271 file · +54 −18Browse files

Unified · Split

git-ref/src/store/file/raw_ext.rs+54−18
@@ -3,7 +3,7 @@ use std::collections::BTreeSet; · 2 unmodified lines
3use git_hash::ObjectId;3use git_hash::ObjectId;
4 4
5use crate::{5use 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
37impl ReferenceExt for Reference {54impl 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 store164 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 }