##// END OF EJS Templates
rust-matchers: fixing cargo doc...
Georges Racinet -
r44458:72bced4f default
parent child Browse files
Show More
@@ -1,178 +1,179 b''
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, DirsMultiset, DirstateMapError};
10 use crate::{utils::hg_path::HgPath, DirsMultiset, DirstateMapError};
11 use std::collections::HashSet;
11 use std::collections::HashSet;
12 use std::iter::FromIterator;
12 use std::iter::FromIterator;
13
13
14 pub enum VisitChildrenSet<'a> {
14 pub enum VisitChildrenSet<'a> {
15 /// Don't visit anything
15 /// Don't visit anything
16 Empty,
16 Empty,
17 /// Only visit this directory
17 /// Only visit this directory
18 This,
18 This,
19 /// Visit this directory and these subdirectories
19 /// Visit this directory and these subdirectories
20 /// TODO Should we implement a `NonEmptyHashSet`?
20 /// TODO Should we implement a `NonEmptyHashSet`?
21 Set(HashSet<&'a HgPath>),
21 Set(HashSet<&'a HgPath>),
22 /// Visit this directory and all subdirectories
22 /// Visit this directory and all subdirectories
23 Recursive,
23 Recursive,
24 }
24 }
25
25
26 pub trait Matcher {
26 pub trait Matcher {
27 /// Explicitly listed files
27 /// Explicitly listed files
28 fn file_set(&self) -> Option<&HashSet<&HgPath>>;
28 fn file_set(&self) -> Option<&HashSet<&HgPath>>;
29 /// Returns whether `filename` is in `file_set`
29 /// Returns whether `filename` is in `file_set`
30 fn exact_match(&self, filename: impl AsRef<HgPath>) -> bool;
30 fn exact_match(&self, filename: impl AsRef<HgPath>) -> bool;
31 /// Returns whether `filename` is matched by this matcher
31 /// Returns whether `filename` is matched by this matcher
32 fn matches(&self, filename: impl AsRef<HgPath>) -> bool;
32 fn matches(&self, filename: impl AsRef<HgPath>) -> bool;
33 /// Decides whether a directory should be visited based on whether it
33 /// Decides whether a directory should be visited based on whether it
34 /// has potential matches in it or one of its subdirectories, and
34 /// has potential matches in it or one of its subdirectories, and
35 /// potentially lists which subdirectories of that directory should be
35 /// potentially lists which subdirectories of that directory should be
36 /// visited. This is based on the match's primary, included, and excluded
36 /// visited. This is based on the match's primary, included, and excluded
37 /// patterns.
37 /// patterns.
38 ///
38 ///
39 /// # Example
39 /// # Example
40 ///
40 ///
41 /// Assume matchers `['path:foo/bar', 'rootfilesin:qux']`, we would
41 /// Assume matchers `['path:foo/bar', 'rootfilesin:qux']`, we would
42 /// return the following values (assuming the implementation of
42 /// return the following values (assuming the implementation of
43 /// visit_children_set is capable of recognizing this; some implementations
43 /// visit_children_set is capable of recognizing this; some implementations
44 /// are not).
44 /// are not).
45 ///
45 ///
46 /// ```text
46 /// ```ignore
47 /// ```ignore
47 /// '' -> {'foo', 'qux'}
48 /// '' -> {'foo', 'qux'}
48 /// 'baz' -> set()
49 /// 'baz' -> set()
49 /// 'foo' -> {'bar'}
50 /// 'foo' -> {'bar'}
50 /// // Ideally this would be `Recursive`, but since the prefix nature of
51 /// // Ideally this would be `Recursive`, but since the prefix nature of
51 /// // matchers is applied to the entire matcher, we have to downgrade this
52 /// // matchers is applied to the entire matcher, we have to downgrade this
52 /// // to `This` due to the (yet to be implemented in Rust) non-prefix
53 /// // to `This` due to the (yet to be implemented in Rust) non-prefix
53 /// // `RootFilesIn'-kind matcher being mixed in.
54 /// // `RootFilesIn'-kind matcher being mixed in.
54 /// 'foo/bar' -> 'this'
55 /// 'foo/bar' -> 'this'
55 /// 'qux' -> 'this'
56 /// 'qux' -> 'this'
56 /// ```
57 /// ```
57 /// # Important
58 /// # Important
58 ///
59 ///
59 /// Most matchers do not know if they're representing files or
60 /// Most matchers do not know if they're representing files or
60 /// directories. They see `['path:dir/f']` and don't know whether `f` is a
61 /// directories. They see `['path:dir/f']` and don't know whether `f` is a
61 /// file or a directory, so `visit_children_set('dir')` for most matchers
62 /// file or a directory, so `visit_children_set('dir')` for most matchers
62 /// will return `HashSet{ HgPath { "f" } }`, but if the matcher knows it's
63 /// will return `HashSet{ HgPath { "f" } }`, but if the matcher knows it's
63 /// a file (like the yet to be implemented in Rust `ExactMatcher` does),
64 /// a file (like the yet to be implemented in Rust `ExactMatcher` does),
64 /// it may return `VisitChildrenSet::This`.
65 /// it may return `VisitChildrenSet::This`.
65 /// Do not rely on the return being a `HashSet` indicating that there are
66 /// Do not rely on the return being a `HashSet` indicating that there are
66 /// no files in this dir to investigate (or equivalently that if there are
67 /// no files in this dir to investigate (or equivalently that if there are
67 /// files to investigate in 'dir' that it will always return
68 /// files to investigate in 'dir' that it will always return
68 /// `VisitChildrenSet::This`).
69 /// `VisitChildrenSet::This`).
69 fn visit_children_set(
70 fn visit_children_set(
70 &self,
71 &self,
71 directory: impl AsRef<HgPath>,
72 directory: impl AsRef<HgPath>,
72 ) -> VisitChildrenSet;
73 ) -> VisitChildrenSet;
73 /// Matcher will match everything and `files_set()` will be empty:
74 /// Matcher will match everything and `files_set()` will be empty:
74 /// optimization might be possible.
75 /// optimization might be possible.
75 fn matches_everything(&self) -> bool;
76 fn matches_everything(&self) -> bool;
76 /// Matcher will match exactly the files in `files_set()`: optimization
77 /// Matcher will match exactly the files in `files_set()`: optimization
77 /// might be possible.
78 /// might be possible.
78 fn is_exact(&self) -> bool;
79 fn is_exact(&self) -> bool;
79 }
80 }
80
81
81 /// Matches everything.
82 /// Matches everything.
82 ///```
83 ///```
83 /// use hg::{ matchers::{Matcher, AlwaysMatcher}, utils::hg_path::HgPath };
84 /// use hg::{ matchers::{Matcher, AlwaysMatcher}, utils::hg_path::HgPath };
84 ///
85 ///
85 /// let matcher = AlwaysMatcher;
86 /// let matcher = AlwaysMatcher;
86 ///
87 ///
87 /// assert_eq!(matcher.matches(HgPath::new(b"whatever")), true);
88 /// assert_eq!(matcher.matches(HgPath::new(b"whatever")), true);
88 /// assert_eq!(matcher.matches(HgPath::new(b"b.txt")), true);
89 /// assert_eq!(matcher.matches(HgPath::new(b"b.txt")), true);
89 /// assert_eq!(matcher.matches(HgPath::new(b"main.c")), true);
90 /// assert_eq!(matcher.matches(HgPath::new(b"main.c")), true);
90 /// assert_eq!(matcher.matches(HgPath::new(br"re:.*\.c$")), true);
91 /// assert_eq!(matcher.matches(HgPath::new(br"re:.*\.c$")), true);
91 /// ```
92 /// ```
92 #[derive(Debug)]
93 #[derive(Debug)]
93 pub struct AlwaysMatcher;
94 pub struct AlwaysMatcher;
94
95
95 impl Matcher for AlwaysMatcher {
96 impl Matcher for AlwaysMatcher {
96 fn file_set(&self) -> Option<&HashSet<&HgPath>> {
97 fn file_set(&self) -> Option<&HashSet<&HgPath>> {
97 None
98 None
98 }
99 }
99 fn exact_match(&self, _filename: impl AsRef<HgPath>) -> bool {
100 fn exact_match(&self, _filename: impl AsRef<HgPath>) -> bool {
100 false
101 false
101 }
102 }
102 fn matches(&self, _filename: impl AsRef<HgPath>) -> bool {
103 fn matches(&self, _filename: impl AsRef<HgPath>) -> bool {
103 true
104 true
104 }
105 }
105 fn visit_children_set(
106 fn visit_children_set(
106 &self,
107 &self,
107 _directory: impl AsRef<HgPath>,
108 _directory: impl AsRef<HgPath>,
108 ) -> VisitChildrenSet {
109 ) -> VisitChildrenSet {
109 VisitChildrenSet::Recursive
110 VisitChildrenSet::Recursive
110 }
111 }
111 fn matches_everything(&self) -> bool {
112 fn matches_everything(&self) -> bool {
112 true
113 true
113 }
114 }
114 fn is_exact(&self) -> bool {
115 fn is_exact(&self) -> bool {
115 false
116 false
116 }
117 }
117 }
118 }
118
119
119 /// Matches the input files exactly. They are interpreted as paths, not
120 /// Matches the input files exactly. They are interpreted as paths, not
120 /// patterns.
121 /// patterns.
121 ///
122 ///
122 ///```
123 ///```
123 /// use hg::{ matchers::{Matcher, FileMatcher}, utils::hg_path::HgPath };
124 /// use hg::{ matchers::{Matcher, FileMatcher}, utils::hg_path::HgPath };
124 ///
125 ///
125 /// let files = [HgPath::new(b"a.txt"), HgPath::new(br"re:.*\.c$")];
126 /// let files = [HgPath::new(b"a.txt"), HgPath::new(br"re:.*\.c$")];
126 /// let matcher = FileMatcher::new(&files).unwrap();
127 /// let matcher = FileMatcher::new(&files).unwrap();
127 ///
128 ///
128 /// assert_eq!(matcher.matches(HgPath::new(b"a.txt")), true);
129 /// assert_eq!(matcher.matches(HgPath::new(b"a.txt")), true);
129 /// assert_eq!(matcher.matches(HgPath::new(b"b.txt")), false);
130 /// assert_eq!(matcher.matches(HgPath::new(b"b.txt")), false);
130 /// assert_eq!(matcher.matches(HgPath::new(b"main.c")), false);
131 /// assert_eq!(matcher.matches(HgPath::new(b"main.c")), false);
131 /// assert_eq!(matcher.matches(HgPath::new(br"re:.*\.c$")), true);
132 /// assert_eq!(matcher.matches(HgPath::new(br"re:.*\.c$")), true);
132 /// ```
133 /// ```
133 #[derive(Debug)]
134 #[derive(Debug)]
134 pub struct FileMatcher<'a> {
135 pub struct FileMatcher<'a> {
135 files: HashSet<&'a HgPath>,
136 files: HashSet<&'a HgPath>,
136 dirs: DirsMultiset,
137 dirs: DirsMultiset,
137 }
138 }
138
139
139 impl<'a> FileMatcher<'a> {
140 impl<'a> FileMatcher<'a> {
140 pub fn new(
141 pub fn new(
141 files: &'a [impl AsRef<HgPath>],
142 files: &'a [impl AsRef<HgPath>],
142 ) -> Result<Self, DirstateMapError> {
143 ) -> Result<Self, DirstateMapError> {
143 Ok(Self {
144 Ok(Self {
144 files: HashSet::from_iter(files.iter().map(|f| f.as_ref())),
145 files: HashSet::from_iter(files.iter().map(|f| f.as_ref())),
145 dirs: DirsMultiset::from_manifest(files)?,
146 dirs: DirsMultiset::from_manifest(files)?,
146 })
147 })
147 }
148 }
148 fn inner_matches(&self, filename: impl AsRef<HgPath>) -> bool {
149 fn inner_matches(&self, filename: impl AsRef<HgPath>) -> bool {
149 self.files.contains(filename.as_ref())
150 self.files.contains(filename.as_ref())
150 }
151 }
151 }
152 }
152
153
153 impl<'a> Matcher for FileMatcher<'a> {
154 impl<'a> Matcher for FileMatcher<'a> {
154 fn file_set(&self) -> Option<&HashSet<&HgPath>> {
155 fn file_set(&self) -> Option<&HashSet<&HgPath>> {
155 Some(&self.files)
156 Some(&self.files)
156 }
157 }
157 fn exact_match(&self, filename: impl AsRef<HgPath>) -> bool {
158 fn exact_match(&self, filename: impl AsRef<HgPath>) -> bool {
158 self.inner_matches(filename)
159 self.inner_matches(filename)
159 }
160 }
160 fn matches(&self, filename: impl AsRef<HgPath>) -> bool {
161 fn matches(&self, filename: impl AsRef<HgPath>) -> bool {
161 self.inner_matches(filename)
162 self.inner_matches(filename)
162 }
163 }
163 fn visit_children_set(
164 fn visit_children_set(
164 &self,
165 &self,
165 _directory: impl AsRef<HgPath>,
166 _directory: impl AsRef<HgPath>,
166 ) -> VisitChildrenSet {
167 ) -> VisitChildrenSet {
167 // TODO implement once we have `status.traverse`
168 // TODO implement once we have `status.traverse`
168 // This is useless until unknown files are taken into account
169 // This is useless until unknown files are taken into account
169 // Which will not need to happen before the `IncludeMatcher`.
170 // Which will not need to happen before the `IncludeMatcher`.
170 unimplemented!()
171 unimplemented!()
171 }
172 }
172 fn matches_everything(&self) -> bool {
173 fn matches_everything(&self) -> bool {
173 false
174 false
174 }
175 }
175 fn is_exact(&self) -> bool {
176 fn is_exact(&self) -> bool {
176 true
177 true
177 }
178 }
178 }
179 }
General Comments 0
You need to be logged in to leave comments. Login now