1use std::fmt::Debug;
2use std::marker::PhantomData;
3
4use crate::opt::Index;
5use crate::opt::Opt;
6use crate::opt::Style;
7use crate::set::SetChecker;
8use crate::set::SetOpt;
9use crate::trace;
10use crate::Error;
11use crate::HashMap;
12use crate::Uid;
13
14pub struct DefaultSetChecker<S>(PhantomData<S>);
17
18impl<S> Clone for DefaultSetChecker<S> {
19 fn clone(&self) -> Self {
20 Self(self.0)
21 }
22}
23
24impl<S> Debug for DefaultSetChecker<S> {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 f.debug_struct("DefaultSetChecker").finish()
27 }
28}
29
30impl<S> Default for DefaultSetChecker<S> {
31 fn default() -> Self {
32 Self(PhantomData)
33 }
34}
35
36impl<S> DefaultSetChecker<S>
37where
38 S: crate::set::Set,
39 SetOpt<S>: Opt,
40{
41 pub fn new() -> Self {
42 Self(PhantomData)
43 }
44
45 pub fn clear(&mut self) {}
46
47 pub fn opt<'a>(set: &'a S, id: &Uid) -> &'a SetOpt<S> {
48 set.get(*id).unwrap()
49 }
50}
51
52impl<S> SetChecker<S> for DefaultSetChecker<S>
53where
54 S: crate::set::Set,
55 SetOpt<S>: Opt,
56{
57 type Error = Error;
58
59 fn pre_check(&self, set: &mut S) -> Result<bool, Error> {
62 let has_cmd = set.iter().any(|opt| opt.mat_style(Style::Cmd));
63
64 const MAX_INDEX: usize = usize::MAX;
65
66 trace!("in pre check {{has_cmd: {}}}", has_cmd);
67 if has_cmd {
68 for opt in set.iter() {
69 if opt.mat_style(Style::Pos) {
70 if let Some(index) = opt.index() {
71 let index = index.calc_index(1, MAX_INDEX).unwrap_or(MAX_INDEX);
72
73 if index == 1 && opt.force() {
74 return Err(Error::unexcepted_pos().with_uid(opt.uid()));
76 }
77 }
78 }
79 }
80 }
81 Ok(true)
82 }
83
84 fn opt_check(&self, set: &mut S) -> Result<bool, Error> {
89 trace!("in opt check, call valid on all Opt ...");
90 for opt in set.iter().filter(|opt| {
91 opt.mat_style(Style::Argument)
92 || opt.mat_style(Style::Boolean)
93 || opt.mat_style(Style::Combined)
94 || opt.mat_style(Style::Flag)
95 }) {
96 if !opt.valid() {
97 return Err(Error::sp_opt_require(vec![opt.hint()]).with_uid(opt.uid()));
98 }
99 }
100 Ok(true)
101 }
102
103 fn pos_check(&self, set: &mut S) -> Result<bool, Error> {
105 let mut index_map = HashMap::<usize, Vec<Uid>>::default();
106 let mut float_vec: Vec<Uid> = vec![];
107
108 const MAX_INDEX: usize = usize::MAX;
109
110 for opt in set.iter() {
111 if opt.mat_style(Style::Pos) {
112 if let Some(index) = opt.index() {
113 match index {
114 Index::Forward(cnt) => {
115 if let Some(index) = index.calc_index(*cnt, MAX_INDEX) {
116 let entry = index_map.entry(index).or_default();
117 entry.push(opt.uid());
118 }
119 }
120 Index::List(v) => {
121 for index in v {
122 let entry = index_map.entry(*index).or_default();
123 entry.push(opt.uid());
124 }
125 }
126 Index::Range(start, Some(end)) => {
127 for index in *start..*end {
128 let entry = index_map.entry(index).or_default();
129 entry.push(opt.uid());
130 }
131 }
132 Index::Backward(_)
133 | Index::Except(_)
134 | Index::Range(_, _)
135 | Index::AnyWhere => {
136 float_vec.push(opt.uid());
137 }
138 Index::Null => {}
139 }
140 }
141 }
142 }
143 let mut names = vec![];
144
145 trace!("in pos check, index: {{{index_map:?}}}, float: {{{float_vec:?}}}");
146 for (_, uids) in index_map {
147 let mut pos_valid = true;
149
150 for uid in uids.iter() {
151 let opt = Self::opt(set, uid);
152 let opt_valid = opt.valid();
153
154 pos_valid = pos_valid && opt_valid;
155 trace!("checking {}: {} {opt:?}", opt.hint(), opt_valid);
156 if !opt_valid {
157 names.push(opt.hint().to_owned());
158 }
159 }
160 if !pos_valid {
161 return Err(Error::sp_pos_require(names).with_uid(uids[0]));
162 }
163 names.clear();
164 }
165 if !float_vec.is_empty() {
166 float_vec
167 .iter()
168 .filter(|&uid| !Self::opt(set, uid).valid())
169 .for_each(|uid| {
170 names.push(Self::opt(set, uid).hint().to_string());
171 });
172 if !names.is_empty() {
173 return Err(Error::sp_pos_require(names).with_uid(float_vec[0]));
174 }
175 }
176 Ok(true)
177 }
178
179 fn cmd_check(&self, set: &mut S) -> Result<bool, Error> {
182 let mut names = vec![];
183 let mut valid = false;
184 let mut uids = vec![];
185
186 for opt in set.iter() {
187 if opt.mat_style(Style::Cmd) {
188 valid = valid || opt.valid();
189 if valid {
190 break;
191 } else {
192 uids.push(opt.uid());
193 names.push(opt.hint().to_owned());
194 }
195 }
196 }
197 trace!("in cmd check, any one of the cmd matched: {}", valid);
198 if !valid && !names.is_empty() {
199 return Err(Error::sp_cmd_require(names).with_uid(uids[0]));
200 }
201 Ok(true)
202 }
203
204 fn post_check(&self, set: &mut S) -> Result<bool, Error> {
206 trace!("in post check, call valid on Main ...");
207 Ok(set
208 .iter()
209 .filter(|opt| opt.mat_style(Style::Main))
210 .all(|opt| opt.valid()))
211 }
212}