| @@ -47,24 +47,29 @@ impl<'a> Display for Outcome<'a> { · 46 unmodified lines |
| 47 | 47 | } |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | | −pub type Error = (); |
| 51 | | − |
| 52 | 50 | pub(crate) mod function { |
| 53 | | − use super::{Error, Outcome}; |
| 51 | + use super::Outcome; |
| 54 | 52 | use git_hash::{oid, ObjectId}; |
| 55 | 53 | use git_object::bstr::BStr; |
| 54 | + use git_object::CommitRefIter; |
| 56 | 55 | use std::borrow::Cow; |
| 57 | | − use std::collections::HashMap; |
| 56 | + use std::collections::{HashMap, VecDeque}; |
| 57 | + use std::iter::FromIterator; |
| 58 | 58 | |
| 59 | 59 | #[allow(clippy::result_unit_err)] |
| 60 | | − pub fn describe<'a>( |
| 60 | + pub fn describe<'a, Find, E>( |
| 61 | 61 | commit: &oid, |
| 62 | + find: Find, |
| 62 | 63 | hex_len: usize, |
| 63 | 64 | name_set: &HashMap<ObjectId, Cow<'a, BStr>>, |
| 64 | | − ) -> Result<Option<Outcome<'a>>, Error> { |
| 65 | + ) -> Result<Option<Outcome<'a>>, E> |
| 66 | + where |
| 67 | + Find: for<'b> FnMut(&oid, &'b mut Vec<u8>) -> Result<CommitRefIter<'b>, E>, |
| 68 | + E: std::error::Error + Send + Sync + 'static, |
| 69 | + { |
| 65 | 70 | if let Some(name) = name_set.get(commit) { |
| 66 | 71 | return Ok(Some(Outcome { |
| 67 | | − name: name.to_owned(), |
| 72 | + name: name.clone(), |
| 68 | 73 | id: commit.to_owned(), |
| 69 | 74 | hex_len, |
| 70 | 75 | depth: 0, |
| @@ -72,6 +77,39 @@ pub(crate) mod function { · 1 unmodified line |
| 72 | 77 | dirty_suffix: None, |
| 73 | 78 | })); |
| 74 | 79 | } |
| 80 | + let mut queue = VecDeque::from_iter(Some(commit.to_owned())); |
| 81 | + let mut candidates = Vec::new(); |
| 82 | + let mut seen_commits = 0; |
| 83 | + let mut gave_up_on_commit = None; |
| 84 | + let mut seen = hash_hasher::HashedSet::default(); |
| 85 | + |
| 86 | + const MAX_CANDIDATES: usize = std::mem::size_of::<usize>() * 8; |
| 87 | + while let Some(commit) = queue.pop_front() { |
| 88 | + seen_commits += 1; |
| 89 | + assert!(seen.insert(commit), "BUG: shouldn't ever see dupes here"); |
| 90 | + if let Some(name) = name_set.get(&commit) { |
| 91 | + if candidates.len() < MAX_CANDIDATES { |
| 92 | + candidates.push(Candidate { |
| 93 | + name: name.clone(), |
| 94 | + depth: seen_commits - 1, |
| 95 | + identity_bit: 1 << candidates.len(), |
| 96 | + order: candidates.len(), |
| 97 | + }); |
| 98 | + } else { |
| 99 | + gave_up_on_commit = Some(commit); |
| 100 | + break; |
| 101 | + } |
| 102 | + } |
| 103 | + } |
| 75 | 104 | todo!("actually search for it") |
| 76 | 105 | } |
| 106 | + |
| 107 | + struct Candidate<'a> { |
| 108 | + name: Cow<'a, BStr>, |
| 109 | + depth: usize, |
| 110 | + /// A single bit identifying this candidate uniquely in a bitset |
| 111 | + identity_bit: usize, |
| 112 | + /// The order at which we found the candidate, first one has order = 0 |
| 113 | + order: usize, |
| 114 | + } |
| 77 | 115 | } |