rust/hg-core/src/matchers.rs
branchstable
changeset 51571 74230abb2504
parent 51570 b39057b713b1
equal deleted inserted replaced
51570:b39057b713b1 51571:74230abb2504
  2144                 path: &'a HgPath,
  2144                 path: &'a HgPath,
  2145                 matching: &'a Tree,
  2145                 matching: &'a Tree,
  2146                 visit_children_set: &'a VisitChildrenSet,
  2146                 visit_children_set: &'a VisitChildrenSet,
  2147             }
  2147             }
  2148 
  2148 
  2149             fn holds(matching: &Tree, vcs: &VisitChildrenSet) -> bool {
  2149             fn holds(
       
  2150                 matching: &Tree,
       
  2151                 not_matching: &Tree,
       
  2152                 vcs: &VisitChildrenSet,
       
  2153             ) -> bool {
  2150                 match vcs {
  2154                 match vcs {
  2151                     VisitChildrenSet::Empty => matching.is_empty(),
  2155                     VisitChildrenSet::Empty => matching.is_empty(),
  2152                     VisitChildrenSet::This => {
  2156                     VisitChildrenSet::This => {
  2153                         // `This` does not come with any obligations.
  2157                         // `This` does not come with any obligations.
  2154                         true
  2158                         true
  2155                     }
  2159                     }
  2156                     VisitChildrenSet::Recursive => {
  2160                     VisitChildrenSet::Recursive => {
  2157                         // `Recursive` does not come with any correctness
  2161                         // `Recursive` requires that *everything* in the
  2158                         // obligations.
  2162                         // subtree matches. This
  2159                         // It instructs the caller to stop calling
  2163                         // requirement is relied on for example in
  2160                         // `visit_children_set` for all
  2164                         // DifferenceMatcher implementation.
  2161                         // descendants, so may have negative performance
  2165                         not_matching.is_empty()
  2162                         // implications, but we're not testing against that
       
  2163                         // here.
       
  2164                         true
       
  2165                     }
  2166                     }
  2166                     VisitChildrenSet::Set(allowed_children) => {
  2167                     VisitChildrenSet::Set(allowed_children) => {
  2167                         // `allowed_children` does not distinguish between
  2168                         // `allowed_children` does not distinguish between
  2168                         // files and directories: if it's not included, it
  2169                         // files and directories: if it's not included, it
  2169                         // must not be matched.
  2170                         // must not be matched.
  2184 
  2185 
  2185             pub fn check<M: Matcher + std::fmt::Debug>(
  2186             pub fn check<M: Matcher + std::fmt::Debug>(
  2186                 matcher: &M,
  2187                 matcher: &M,
  2187                 path: &HgPath,
  2188                 path: &HgPath,
  2188                 matching: &Tree,
  2189                 matching: &Tree,
       
  2190                 not_matching: &Tree,
  2189                 visit_children_set: &VisitChildrenSet,
  2191                 visit_children_set: &VisitChildrenSet,
  2190             ) {
  2192             ) {
  2191                 if !holds(matching, visit_children_set) {
  2193                 if !holds(matching, not_matching, visit_children_set) {
  2192                     panic!(
  2194                     panic!(
  2193                         "{:#?}",
  2195                         "{:#?}",
  2194                         Error {
  2196                         Error {
  2195                             matcher,
  2197                             matcher,
  2196                             path,
  2198                             path,
  2221 
  2223 
  2222         fn is_empty(&self) -> bool {
  2224         fn is_empty(&self) -> bool {
  2223             self.files.is_empty() && self.dirs.is_empty()
  2225             self.files.is_empty() && self.dirs.is_empty()
  2224         }
  2226         }
  2225 
  2227 
       
  2228         fn make(
       
  2229             files: BTreeSet<HgPathBuf>,
       
  2230             dirs: BTreeMap<HgPathBuf, Tree>,
       
  2231         ) -> Self {
       
  2232             Self {
       
  2233                 files,
       
  2234                 dirs: dirs
       
  2235                     .into_iter()
       
  2236                     .filter(|(_k, v)| (!(v.is_empty())))
       
  2237                     .collect(),
       
  2238             }
       
  2239         }
       
  2240 
  2226         fn filter_and_check<M: Matcher + Debug>(
  2241         fn filter_and_check<M: Matcher + Debug>(
  2227             &self,
  2242             &self,
  2228             m: &M,
  2243             m: &M,
  2229             path: &HgPath,
  2244             path: &HgPath,
  2230         ) -> Self {
  2245         ) -> (Self, Self) {
  2231             let files: BTreeSet<HgPathBuf> = self
  2246             let (files1, files2): (BTreeSet<HgPathBuf>, BTreeSet<HgPathBuf>) =
  2232                 .files
  2247                 self.files
  2233                 .iter()
  2248                     .iter()
  2234                 .filter(|v| m.matches(&path.join(v)))
  2249                     .map(|v| v.to_owned())
  2235                 .map(|f| f.to_owned())
  2250                     .partition(|v| m.matches(&path.join(v)));
  2236                 .collect();
  2251             let (dirs1, dirs2): (
  2237             let dirs: BTreeMap<HgPathBuf, Tree> = self
  2252                 BTreeMap<HgPathBuf, Tree>,
       
  2253                 BTreeMap<HgPathBuf, Tree>,
       
  2254             ) = self
  2238                 .dirs
  2255                 .dirs
  2239                 .iter()
  2256                 .iter()
  2240                 .filter_map(|(k, v)| {
  2257                 .map(|(k, v)| {
  2241                     let path = path.join(k);
  2258                     let path = path.join(k);
  2242                     let v = v.filter_and_check(m, &path);
  2259                     let (t1, t2) = v.filter_and_check(m, &path);
  2243                     if v.is_empty() {
  2260                     ((k.clone(), t1), (k.clone(), t2))
  2244                         None
       
  2245                     } else {
       
  2246                         Some((k.to_owned(), v))
       
  2247                     }
       
  2248                 })
  2261                 })
  2249                 .collect();
  2262                 .unzip();
  2250             let matching = Self { files, dirs };
  2263             let matching = Self::make(files1, dirs1);
       
  2264             let not_matching = Self::make(files2, dirs2);
  2251             let vcs = m.visit_children_set(path);
  2265             let vcs = m.visit_children_set(path);
  2252             invariants::visit_children_set::check(m, path, &matching, &vcs);
  2266             invariants::visit_children_set::check(
  2253             matching
  2267                 m,
       
  2268                 path,
       
  2269                 &matching,
       
  2270                 &not_matching,
       
  2271                 &vcs,
       
  2272             );
       
  2273             (matching, not_matching)
  2254         }
  2274         }
  2255 
  2275 
  2256         fn check_matcher<M: Matcher + Debug>(
  2276         fn check_matcher<M: Matcher + Debug>(
  2257             &self,
  2277             &self,
  2258             m: &M,
  2278             m: &M,
  2259             expect_count: usize,
  2279             expect_count: usize,
  2260         ) {
  2280         ) {
  2261             let res = self.filter_and_check(m, &HgPathBuf::new());
  2281             let res = self.filter_and_check(m, &HgPathBuf::new());
  2262             if expect_count != res.len() {
  2282             if expect_count != res.0.len() {
  2263                 eprintln!(
  2283                 eprintln!(
  2264                     "warning: expected {} matches, got {} for {:#?}",
  2284                     "warning: expected {} matches, got {} for {:#?}",
  2265                     expect_count,
  2285                     expect_count,
  2266                     res.len(),
  2286                     res.0.len(),
  2267                     m
  2287                     m
  2268                 );
  2288                 );
  2269             }
  2289             }
  2270         }
  2290         }
  2271     }
  2291     }