This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / knot2 / third_party / gix-pack / src / find_traits.rs
13 kB 343 lines
1use crate::{data, find}; 2 3/// Describe how object can be located in an object store with built-in facilities to supports packs specifically. 4/// 5/// ## Notes 6/// 7/// Find effectively needs [generic associated types][issue] to allow a trait for the returned object type. 8/// Until then, we will have to make due with explicit types and give them the potentially added features we want. 9/// 10/// Furthermore, despite this trait being in `gix-pack`, it leaks knowledge about objects potentially not being packed. 11/// This is a necessary trade-off to allow this trait to live in `gix-pack` where it is used in functions to create a pack. 12/// 13/// [issue]: https://github.com/rust-lang/rust/issues/44265 14pub trait Find { 15 /// Returns true if the object exists in the database. 16 fn contains(&self, id: &gix_hash::oid) -> bool; 17 18 /// Find an object matching `id` in the database while placing its raw, decoded data into `buffer`. 19 /// A `pack_cache` can be used to speed up subsequent lookups, set it to [`crate::cache::Never`] if the 20 /// workload isn't suitable for caching. 21 /// 22 /// Returns `Some((<object data>, <pack location if packed>))` if it was present in the database, 23 /// or the error that occurred during lookup or object retrieval. 24 fn try_find<'a>( 25 &self, 26 id: &gix_hash::oid, 27 buffer: &'a mut Vec<u8>, 28 ) -> Result< 29 Option<(gix_object::Data<'a>, Option<data::entry::Location>)>, 30 gix_object::find::Error, 31 > { 32 self.try_find_cached(id, buffer, &mut crate::cache::Never) 33 } 34 35 /// Like [`Find::try_find()`], but with support for controlling the pack cache. 36 /// A `pack_cache` can be used to speed up subsequent lookups, set it to [`crate::cache::Never`] if the 37 /// workload isn't suitable for caching. 38 /// 39 /// Returns `Some((<object data>, <pack location if packed>))` if it was present in the database, 40 /// or the error that occurred during lookup or object retrieval. 41 fn try_find_cached<'a>( 42 &self, 43 id: &gix_hash::oid, 44 buffer: &'a mut Vec<u8>, 45 pack_cache: &mut dyn crate::cache::DecodeEntry, 46 ) -> Result< 47 Option<(gix_object::Data<'a>, Option<data::entry::Location>)>, 48 gix_object::find::Error, 49 >; 50 51 /// Find the packs location where an object with `id` can be found in the database, or `None` if there is no pack 52 /// holding the object. 53 /// 54 /// _Note_ that this is always None if the object isn't packed even though it exists as loose object. 55 fn location_by_oid( 56 &self, 57 id: &gix_hash::oid, 58 buf: &mut Vec<u8>, 59 ) -> Option<data::entry::Location>; 60 61 /// Obtain a vector of all offsets, in index order, along with their object id. 62 fn pack_offsets_and_oid(&self, pack_id: u32) 63 -> Option<Vec<(data::Offset, gix_hash::ObjectId)>>; 64 65 /// Return the [`find::Entry`] for `location` if it is backed by a pack. 66 /// 67 /// Note that this is only in the interest of avoiding duplicate work during pack generation. 68 /// Pack locations can be obtained from [`Find::try_find()`]. 69 /// 70 /// # Notes 71 /// 72 /// Custom implementations might be interested in providing their own meta-data with `object`, 73 /// which currently isn't possible as the `Locate` trait requires GATs to work like that. 74 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry>; 75} 76 77mod ext { 78 use gix_object::{ 79 BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, 80 TreeRefIter, 81 }; 82 83 macro_rules! make_obj_lookup { 84 ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => { 85 /// Like [`find(…)`][Self::find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error 86 /// while returning the desired object type. 87 fn $method<'a>( 88 &self, 89 id: &gix_hash::oid, 90 buffer: &'a mut Vec<u8>, 91 ) -> Result< 92 ($object_type, Option<crate::data::entry::Location>), 93 gix_object::find::existing_object::Error, 94 > { 95 let id = id.as_ref(); 96 self.try_find(id, buffer) 97 .map_err(gix_object::find::existing_object::Error::Find)? 98 .ok_or_else(|| gix_object::find::existing_object::Error::NotFound { 99 oid: id.as_ref().to_owned(), 100 }) 101 .and_then(|(o, l)| { 102 o.decode() 103 .map_err(|err| gix_object::find::existing_object::Error::Decode { 104 source: err, 105 oid: id.to_owned(), 106 }) 107 .map(|o| (o, l)) 108 }) 109 .and_then(|(o, l)| match o { 110 $object_variant(o) => return Ok((o, l)), 111 o => Err(gix_object::find::existing_object::Error::ObjectKind { 112 oid: id.to_owned(), 113 actual: o.kind(), 114 expected: $object_kind, 115 }), 116 }) 117 } 118 }; 119 } 120 121 macro_rules! make_iter_lookup { 122 ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => { 123 /// Like [`find(…)`][Self::find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error 124 /// while returning the desired iterator type. 125 fn $method<'a>( 126 &self, 127 id: &gix_hash::oid, 128 buffer: &'a mut Vec<u8>, 129 ) -> Result< 130 ($object_type, Option<crate::data::entry::Location>), 131 gix_object::find::existing_iter::Error, 132 > { 133 let id = id.as_ref(); 134 self.try_find(id, buffer) 135 .map_err(gix_object::find::existing_iter::Error::Find)? 136 .ok_or_else(|| gix_object::find::existing_iter::Error::NotFound { 137 oid: id.as_ref().to_owned(), 138 }) 139 .and_then(|(o, l)| { 140 o.$into_iter() 141 .ok_or_else(|| gix_object::find::existing_iter::Error::ObjectKind { 142 oid: id.to_owned(), 143 actual: o.kind, 144 expected: $object_kind, 145 }) 146 .map(|i| (i, l)) 147 }) 148 } 149 }; 150 } 151 152 /// An extension trait with convenience functions. 153 pub trait FindExt: super::Find { 154 /// Like [`try_find(…)`][super::Find::try_find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error. 155 fn find<'a>( 156 &self, 157 id: &gix_hash::oid, 158 buffer: &'a mut Vec<u8>, 159 ) -> Result< 160 (gix_object::Data<'a>, Option<crate::data::entry::Location>), 161 gix_object::find::existing::Error, 162 > { 163 self.try_find(id, buffer) 164 .map_err(gix_object::find::existing::Error::Find)? 165 .ok_or_else(|| gix_object::find::existing::Error::NotFound { 166 oid: id.as_ref().to_owned(), 167 }) 168 } 169 170 make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>); 171 make_obj_lookup!(find_tree, ObjectRef::Tree, Kind::Tree, TreeRef<'a>); 172 make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>); 173 make_obj_lookup!(find_blob, ObjectRef::Blob, Kind::Blob, BlobRef<'a>); 174 make_iter_lookup!( 175 find_commit_iter, 176 Kind::Blob, 177 CommitRefIter<'a>, 178 try_into_commit_iter 179 ); 180 make_iter_lookup!( 181 find_tree_iter, 182 Kind::Tree, 183 TreeRefIter<'a>, 184 try_into_tree_iter 185 ); 186 make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter); 187 } 188 189 impl<T: super::Find + ?Sized> FindExt for T {} 190} 191pub use ext::FindExt; 192 193mod find_impls { 194 use std::{ops::Deref, rc::Rc}; 195 196 use gix_hash::oid; 197 198 use crate::{data, find}; 199 200 impl<T> crate::Find for &T 201 where 202 T: crate::Find, 203 { 204 fn contains(&self, id: &oid) -> bool { 205 (*self).contains(id) 206 } 207 208 fn try_find_cached<'a>( 209 &self, 210 id: &oid, 211 buffer: &'a mut Vec<u8>, 212 pack_cache: &mut dyn crate::cache::DecodeEntry, 213 ) -> Result< 214 Option<(gix_object::Data<'a>, Option<data::entry::Location>)>, 215 gix_object::find::Error, 216 > { 217 (*self).try_find_cached(id, buffer, pack_cache) 218 } 219 220 fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Option<data::entry::Location> { 221 (*self).location_by_oid(id, buf) 222 } 223 224 fn pack_offsets_and_oid( 225 &self, 226 pack_id: u32, 227 ) -> Option<Vec<(data::Offset, gix_hash::ObjectId)>> { 228 (*self).pack_offsets_and_oid(pack_id) 229 } 230 231 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> { 232 (*self).entry_by_location(location) 233 } 234 } 235 236 impl<T> super::Find for std::sync::Arc<T> 237 where 238 T: super::Find, 239 { 240 fn contains(&self, id: &oid) -> bool { 241 self.deref().contains(id) 242 } 243 244 fn try_find_cached<'a>( 245 &self, 246 id: &oid, 247 buffer: &'a mut Vec<u8>, 248 pack_cache: &mut dyn crate::cache::DecodeEntry, 249 ) -> Result< 250 Option<(gix_object::Data<'a>, Option<data::entry::Location>)>, 251 gix_object::find::Error, 252 > { 253 self.deref().try_find_cached(id, buffer, pack_cache) 254 } 255 256 fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Option<data::entry::Location> { 257 self.deref().location_by_oid(id, buf) 258 } 259 260 fn pack_offsets_and_oid( 261 &self, 262 pack_id: u32, 263 ) -> Option<Vec<(data::Offset, gix_hash::ObjectId)>> { 264 self.deref().pack_offsets_and_oid(pack_id) 265 } 266 267 fn entry_by_location(&self, object: &data::entry::Location) -> Option<find::Entry> { 268 self.deref().entry_by_location(object) 269 } 270 } 271 272 impl<T> super::Find for Rc<T> 273 where 274 T: super::Find, 275 { 276 fn contains(&self, id: &oid) -> bool { 277 self.deref().contains(id) 278 } 279 280 fn try_find_cached<'a>( 281 &self, 282 id: &oid, 283 buffer: &'a mut Vec<u8>, 284 pack_cache: &mut dyn crate::cache::DecodeEntry, 285 ) -> Result< 286 Option<(gix_object::Data<'a>, Option<data::entry::Location>)>, 287 gix_object::find::Error, 288 > { 289 self.deref().try_find_cached(id, buffer, pack_cache) 290 } 291 292 fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Option<data::entry::Location> { 293 self.deref().location_by_oid(id, buf) 294 } 295 296 fn pack_offsets_and_oid( 297 &self, 298 pack_id: u32, 299 ) -> Option<Vec<(data::Offset, gix_hash::ObjectId)>> { 300 self.deref().pack_offsets_and_oid(pack_id) 301 } 302 303 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> { 304 self.deref().entry_by_location(location) 305 } 306 } 307 308 impl<T> super::Find for Box<T> 309 where 310 T: super::Find, 311 { 312 fn contains(&self, id: &oid) -> bool { 313 self.deref().contains(id) 314 } 315 316 fn try_find_cached<'a>( 317 &self, 318 id: &oid, 319 buffer: &'a mut Vec<u8>, 320 pack_cache: &mut dyn crate::cache::DecodeEntry, 321 ) -> Result< 322 Option<(gix_object::Data<'a>, Option<data::entry::Location>)>, 323 gix_object::find::Error, 324 > { 325 self.deref().try_find_cached(id, buffer, pack_cache) 326 } 327 328 fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Option<data::entry::Location> { 329 self.deref().location_by_oid(id, buf) 330 } 331 332 fn pack_offsets_and_oid( 333 &self, 334 pack_id: u32, 335 ) -> Option<Vec<(data::Offset, gix_hash::ObjectId)>> { 336 self.deref().pack_offsets_and_oid(pack_id) 337 } 338 339 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> { 340 self.deref().entry_by_location(location) 341 } 342 } 343}