##// END OF EJS Templates
rust-matchers: improve `Matcher` trait ergonomics...
Raphaël Gomès -
r44284:1bb4e9b0 default
parent child Browse files
Show More
@@ -1,106 +1,106
1 // matchers.rs
1 // matchers.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! Structs and types for matching files and directories.
8 //! Structs and types for matching files and directories.
9
9
10 use crate::utils::hg_path::{HgPath, HgPathBuf};
10 use crate::utils::hg_path::{HgPath, HgPathBuf};
11 use std::collections::HashSet;
11 use std::collections::HashSet;
12
12
13 pub enum VisitChildrenSet {
13 pub enum VisitChildrenSet<'a> {
14 /// Don't visit anything
14 /// Don't visit anything
15 Empty,
15 Empty,
16 /// Only visit this directory
16 /// Only visit this directory
17 This,
17 This,
18 /// Visit this directory and these subdirectories
18 /// Visit this directory and these subdirectories
19 /// TODO Should we implement a `NonEmptyHashSet`?
19 /// TODO Should we implement a `NonEmptyHashSet`?
20 Set(HashSet<HgPathBuf>),
20 Set(HashSet<&'a HgPath>),
21 /// Visit this directory and all subdirectories
21 /// Visit this directory and all subdirectories
22 Recursive,
22 Recursive,
23 }
23 }
24
24
25 pub trait Matcher {
25 pub trait Matcher {
26 /// Explicitly listed files
26 /// Explicitly listed files
27 fn file_set(&self) -> HashSet<&HgPath>;
27 fn file_set(&self) -> Option<&HashSet<&HgPath>>;
28 /// Returns whether `filename` is in `file_set`
28 /// Returns whether `filename` is in `file_set`
29 fn exact_match(&self, filename: impl AsRef<HgPath>) -> bool;
29 fn exact_match(&self, filename: impl AsRef<HgPath>) -> bool;
30 /// Returns whether `filename` is matched by this matcher
30 /// Returns whether `filename` is matched by this matcher
31 fn matches(&self, filename: impl AsRef<HgPath>) -> bool;
31 fn matches(&self, filename: impl AsRef<HgPath>) -> bool;
32 /// Decides whether a directory should be visited based on whether it
32 /// Decides whether a directory should be visited based on whether it
33 /// has potential matches in it or one of its subdirectories, and
33 /// has potential matches in it or one of its subdirectories, and
34 /// potentially lists which subdirectories of that directory should be
34 /// potentially lists which subdirectories of that directory should be
35 /// visited. This is based on the match's primary, included, and excluded
35 /// visited. This is based on the match's primary, included, and excluded
36 /// patterns.
36 /// patterns.
37 ///
37 ///
38 /// # Example
38 /// # Example
39 ///
39 ///
40 /// Assume matchers `['path:foo/bar', 'rootfilesin:qux']`, we would
40 /// Assume matchers `['path:foo/bar', 'rootfilesin:qux']`, we would
41 /// return the following values (assuming the implementation of
41 /// return the following values (assuming the implementation of
42 /// visit_children_set is capable of recognizing this; some implementations
42 /// visit_children_set is capable of recognizing this; some implementations
43 /// are not).
43 /// are not).
44 ///
44 ///
45 /// ```ignore
45 /// ```ignore
46 /// '' -> {'foo', 'qux'}
46 /// '' -> {'foo', 'qux'}
47 /// 'baz' -> set()
47 /// 'baz' -> set()
48 /// 'foo' -> {'bar'}
48 /// 'foo' -> {'bar'}
49 /// // Ideally this would be `Recursive`, but since the prefix nature of
49 /// // Ideally this would be `Recursive`, but since the prefix nature of
50 /// // matchers is applied to the entire matcher, we have to downgrade this
50 /// // matchers is applied to the entire matcher, we have to downgrade this
51 /// // to `This` due to the (yet to be implemented in Rust) non-prefix
51 /// // to `This` due to the (yet to be implemented in Rust) non-prefix
52 /// // `RootFilesIn'-kind matcher being mixed in.
52 /// // `RootFilesIn'-kind matcher being mixed in.
53 /// 'foo/bar' -> 'this'
53 /// 'foo/bar' -> 'this'
54 /// 'qux' -> 'this'
54 /// 'qux' -> 'this'
55 /// ```
55 /// ```
56 /// # Important
56 /// # Important
57 ///
57 ///
58 /// Most matchers do not know if they're representing files or
58 /// Most matchers do not know if they're representing files or
59 /// directories. They see `['path:dir/f']` and don't know whether `f` is a
59 /// directories. They see `['path:dir/f']` and don't know whether `f` is a
60 /// file or a directory, so `visit_children_set('dir')` for most matchers
60 /// file or a directory, so `visit_children_set('dir')` for most matchers
61 /// will return `HashSet{ HgPath { "f" } }`, but if the matcher knows it's
61 /// will return `HashSet{ HgPath { "f" } }`, but if the matcher knows it's
62 /// a file (like the yet to be implemented in Rust `ExactMatcher` does),
62 /// a file (like the yet to be implemented in Rust `ExactMatcher` does),
63 /// it may return `VisitChildrenSet::This`.
63 /// it may return `VisitChildrenSet::This`.
64 /// Do not rely on the return being a `HashSet` indicating that there are
64 /// Do not rely on the return being a `HashSet` indicating that there are
65 /// no files in this dir to investigate (or equivalently that if there are
65 /// no files in this dir to investigate (or equivalently that if there are
66 /// files to investigate in 'dir' that it will always return
66 /// files to investigate in 'dir' that it will always return
67 /// `VisitChildrenSet::This`).
67 /// `VisitChildrenSet::This`).
68 fn visit_children_set(
68 fn visit_children_set(
69 &self,
69 &self,
70 directory: impl AsRef<HgPath>,
70 directory: impl AsRef<HgPath>,
71 ) -> VisitChildrenSet;
71 ) -> VisitChildrenSet;
72 /// Matcher will match everything and `files_set()` will be empty:
72 /// Matcher will match everything and `files_set()` will be empty:
73 /// optimization might be possible.
73 /// optimization might be possible.
74 fn matches_everything(&self) -> bool;
74 fn matches_everything(&self) -> bool;
75 /// Matcher will match exactly the files in `files_set()`: optimization
75 /// Matcher will match exactly the files in `files_set()`: optimization
76 /// might be possible.
76 /// might be possible.
77 fn is_exact(&self) -> bool;
77 fn is_exact(&self) -> bool;
78 }
78 }
79
79
80 /// Matches everything.
80 /// Matches everything.
81 #[derive(Debug)]
81 #[derive(Debug)]
82 pub struct AlwaysMatcher;
82 pub struct AlwaysMatcher;
83
83
84 impl Matcher for AlwaysMatcher {
84 impl Matcher for AlwaysMatcher {
85 fn file_set(&self) -> HashSet<&HgPath> {
85 fn file_set(&self) -> Option<&HashSet<&HgPath>> {
86 HashSet::new()
86 None
87 }
87 }
88 fn exact_match(&self, _filename: impl AsRef<HgPath>) -> bool {
88 fn exact_match(&self, _filename: impl AsRef<HgPath>) -> bool {
89 false
89 false
90 }
90 }
91 fn matches(&self, _filename: impl AsRef<HgPath>) -> bool {
91 fn matches(&self, _filename: impl AsRef<HgPath>) -> bool {
92 true
92 true
93 }
93 }
94 fn visit_children_set(
94 fn visit_children_set(
95 &self,
95 &self,
96 _directory: impl AsRef<HgPath>,
96 _directory: impl AsRef<HgPath>,
97 ) -> VisitChildrenSet {
97 ) -> VisitChildrenSet {
98 VisitChildrenSet::Recursive
98 VisitChildrenSet::Recursive
99 }
99 }
100 fn matches_everything(&self) -> bool {
100 fn matches_everything(&self) -> bool {
101 true
101 true
102 }
102 }
103 fn is_exact(&self) -> bool {
103 fn is_exact(&self) -> bool {
104 false
104 false
105 }
105 }
106 }
106 }
General Comments 0
You need to be logged in to leave comments. Login now