Sebastian Thielmake fmt429cccc4 years agoHistory
112 lines · 3.9 KB · Rust
RawDownload
use std::collections::BTreeSet; use crate::{parse::Operation, types::Mode, MatchGroup, RefSpecRef}; pub(crate) mod types;pub use types::{Item, Mapping, Outcome, Source, SourceRef}; ///pub mod validate; /// Initializationimpl<'a> MatchGroup<'a> {    /// Take all the fetch ref specs from `specs` get a match group ready.    pub fn from_fetch_specs(specs: impl IntoIterator<Item = RefSpecRef<'a>>) -> Self {        MatchGroup {            specs: specs.into_iter().filter(|s| s.op == Operation::Fetch).collect(),        }    }} /// Matchingimpl<'a> MatchGroup<'a> {    /// Match all `items` against all fetch specs present in this group, returning deduplicated mappings from source to destination.    /// Note that this method only makes sense if the specs are indeed fetch specs and may panic otherwise.    ///    /// Note that negative matches are not part of the return value, so they are not observable but will be used to remove mappings.    pub fn match_remotes<'item>(self, mut items: impl Iterator<Item = Item<'item>> + Clone) -> Outcome<'a, 'item> {        let mut out = Vec::new();        let mut seen = BTreeSet::default();        let mut push_unique = |mapping| {            if seen.insert(calculate_hash(&mapping)) {                out.push(mapping);            }        };        let mut matchers: Vec<Option<Matcher<'_>>> = self            .specs            .iter()            .copied()            .map(Matcher::from)            .enumerate()            .map(|(idx, m)| match m.lhs {                Some(Needle::Object(id)) => {                    push_unique(Mapping {                        item_index: None,                        lhs: SourceRef::ObjectId(id),                        rhs: m.rhs.map(|n| n.to_bstr()),                        spec_index: idx,                    });                    None                }                _ => Some(m),            })            .collect();         let mut has_negation = false;        for (spec_index, (spec, matcher)) in self.specs.iter().zip(matchers.iter_mut()).enumerate() {            for (item_index, item) in items.clone().enumerate() {                if spec.mode == Mode::Negative {                    has_negation = true;                    continue;                }                if let Some(matcher) = matcher {                    let (matched, rhs) = matcher.matches_lhs(item);                    if matched {                        push_unique(Mapping {                            item_index: Some(item_index),                            lhs: SourceRef::FullName(item.full_ref_name),                            rhs,                            spec_index,                        })                    }                }            }        }         if let Some(id) = has_negation.then(|| items.next().map(|i| i.target)).flatten() {            let null_id = git_hash::ObjectId::null(id.kind());            for matcher in matchers                .into_iter()                .zip(self.specs.iter())                .filter_map(|(m, spec)| m.and_then(|m| (spec.mode == Mode::Negative).then(|| m)))            {                out.retain(|m| match m.lhs {                    SourceRef::ObjectId(_) => true,                    SourceRef::FullName(name) => {                        !matcher                            .matches_lhs(Item {                                full_ref_name: name,                                target: &null_id,                                object: None,                            })                            .0                    }                });            }        }        Outcome {            group: self,            mappings: out,        }    }} fn calculate_hash<T: std::hash::Hash>(t: &T) -> u64 {    use std::hash::Hasher;    let mut s = std::collections::hash_map::DefaultHasher::new();    t.hash(&mut s);    s.finish()} mod util;use util::{Matcher, Needle};