url_cleaner_engine/types/conditions.rs
1//! Logic for when a [`TaskState`] should be modified.
2
3use thiserror::Error;
4use serde::{Serialize, Deserialize};
5#[expect(unused_imports, reason = "Used in doc comments.")]
6use url::Url;
7
8use crate::types::*;
9use crate::util::*;
10
11/// Conditions that decide if and when to apply an [`Action`].
12///
13/// - "*IsOneOf" variants should always be equivalent to a [`Self::Any`] with a respective "*Is" variant for each value in the [`Set`].
14///
15/// - "*IsInSet" variants should always be equivalent to moving the [`Set`] from [`Params::sets`] to the respective "*IsOneOf" variant.
16#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Suitability)]
17#[serde(deny_unknown_fields)]
18pub enum Condition {
19 // Debug/constants
20
21 /// Always satisfied.
22 /// # Examples
23 /// ```
24 /// use url_cleaner_engine::types::*;
25 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com");
26 ///
27 /// assert!(Condition::Always.check(&task_state).unwrap());
28 /// ```
29 Always,
30 /// Never satisfied.
31 /// # Examples
32 /// ```
33 /// use url_cleaner_engine::types::*;
34 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com");
35 ///
36 /// assert!(!Condition::Never.check(&task_state).unwrap());
37 /// ```
38 Never,
39 /// Always returns the error [`ConditionError::ExplicitError`] with the included message.
40 /// # Errors
41 /// Always returns the error [`ConditionError::ExplicitError`].
42 /// # Examples
43 /// ```
44 /// use url_cleaner_engine::types::*;
45 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com");
46 ///
47 /// Condition::Error("...".into()).check(&task_state).unwrap_err();
48 /// ```
49 Error(String),
50 /// Prints debug info about the contained [`Self`] and the current [`TaskState`], then returns its return value.
51 /// # Errors
52 /// If the call to [`Self::check`] returns an error, that error is returned after the debug info is printed.
53 #[suitable(never)]
54 Debug(Box<Self>),
55
56 // Logic
57
58 /// If [`Self::If::if`] is satisfied, return the value of [`Self::If::then`].
59 ///
60 /// If [`Self::If::if`] is unsatisfied, return the value of [`Self::If::else`].
61 /// # Errors
62 #[doc = edoc!(checkerr(Self, 2))]
63 /// # Examples
64 /// ```
65 /// use url_cleaner_engine::types::*;
66 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com");
67 ///
68 /// assert!( Condition::If {r#if: Box::new(Condition::Always), then: Box::new(Condition::Always), r#else: Some(Box::new(Condition::Always))}.check(&task_state).unwrap());
69 /// assert!( Condition::If {r#if: Box::new(Condition::Always), then: Box::new(Condition::Always), r#else: Some(Box::new(Condition::Never ))}.check(&task_state).unwrap());
70 /// assert!(!Condition::If {r#if: Box::new(Condition::Always), then: Box::new(Condition::Never ), r#else: Some(Box::new(Condition::Always))}.check(&task_state).unwrap());
71 /// assert!(!Condition::If {r#if: Box::new(Condition::Always), then: Box::new(Condition::Never ), r#else: Some(Box::new(Condition::Never ))}.check(&task_state).unwrap());
72 /// assert!( Condition::If {r#if: Box::new(Condition::Never ), then: Box::new(Condition::Always), r#else: Some(Box::new(Condition::Always))}.check(&task_state).unwrap());
73 /// assert!(!Condition::If {r#if: Box::new(Condition::Never ), then: Box::new(Condition::Always), r#else: Some(Box::new(Condition::Never ))}.check(&task_state).unwrap());
74 /// assert!( Condition::If {r#if: Box::new(Condition::Never ), then: Box::new(Condition::Never ), r#else: Some(Box::new(Condition::Always))}.check(&task_state).unwrap());
75 /// assert!(!Condition::If {r#if: Box::new(Condition::Never ), then: Box::new(Condition::Never ), r#else: Some(Box::new(Condition::Never ))}.check(&task_state).unwrap());
76 /// ```
77 If {
78 /// The [`Self`] to decide between [`Self::If::then`] and [`Self::If::else`].
79 r#if: Box<Self>,
80 /// The [`Self`] to use if [`Self::If::if`] is satisfied.
81 then: Box<Self>,
82 /// The [`Self`] to use if [`Self::If::if`] is unsatisfied.
83 #[serde(default, skip_serializing_if = "is_default")]
84 r#else: Option<Box<Self>>
85 },
86 /// Inverts the satisfaction of the contained [`Self`].
87 /// # Errors
88 #[doc = edoc!(checkerr(Self))]
89 /// # Examples
90 /// ```
91 /// use url_cleaner_engine::types::*;
92 /// url_cleaner_engine::task_state_view!(task_state);
93 ///
94 /// assert!(!Condition::Not(Box::new(Condition::Always)).check(&task_state).unwrap());
95 /// assert!( Condition::Not(Box::new(Condition::Never )).check(&task_state).unwrap());
96 /// ```
97 Not(Box<Self>),
98 /// Satisfied if all contained [`Self`]s are satisfied.
99 /// # Errors
100 #[doc = edoc!(checkerr(Self, 3))]
101 /// # Examples
102 /// ```
103 /// use url_cleaner_engine::types::*;
104 /// url_cleaner_engine::task_state_view!(task_state);
105 ///
106 /// assert!(!Condition::All(vec![Condition::Never , Condition::Never ]).check(&task_state).unwrap());
107 /// assert!(!Condition::All(vec![Condition::Never , Condition::Always]).check(&task_state).unwrap());
108 /// assert!(!Condition::All(vec![Condition::Always, Condition::Never ]).check(&task_state).unwrap());
109 /// assert!( Condition::All(vec![Condition::Always, Condition::Always]).check(&task_state).unwrap());
110 /// ```
111 All(Vec<Self>),
112 /// Satisfied if any contained [`Self`] is satisfied.
113 /// # Errors
114 #[doc = edoc!(checkerr(Self, 3))]
115 /// # Examples
116 /// ```
117 /// use url_cleaner_engine::types::*;
118 /// url_cleaner_engine::task_state_view!(task_state);
119 ///
120 /// assert!(!Condition::Any(vec![Condition::Never , Condition::Never ]).check(&task_state).unwrap());
121 /// assert!( Condition::Any(vec![Condition::Never , Condition::Always]).check(&task_state).unwrap());
122 /// assert!( Condition::Any(vec![Condition::Always, Condition::Never ]).check(&task_state).unwrap());
123 /// assert!( Condition::Any(vec![Condition::Always, Condition::Always]).check(&task_state).unwrap());
124 /// ```
125 Any(Vec<Self>),
126
127 // Error handling
128
129 /// Satisfied if the contained [`Self`] is satisfied or errors.
130 ErrorToSatisfied(Box<Self>),
131 /// Satisfied if the contained [`Self`] is satisfied.
132 ///
133 /// Unsatisfied if the contained [`Self`] errors.
134 ErrorToUnsatisfied(Box<Self>),
135 /// If [`Self::TryElse::try`]'s call to [`Self::check`] returns an error, return the value of [`Self::TryElse::else`].
136 /// # Errors
137 #[doc = edoc!(checkerrte(Self, Condition))]
138 TryElse {
139 /// The [`Self`] to try first.
140 r#try: Box<Self>,
141 /// The [`Self`] to try if [`Self::TryElse::try`] returns an error.
142 r#else: Box<Self>
143 },
144
145 // Maps
146
147 /// Gets the value specified by [`Self::PartMap::part`], indexes [`Self::PartMap::map`], and returns the value of the returned [`Self`].
148 ///
149 /// If the call to [`Map::get`] returns [`None`], fails.
150 /// # Errors
151 #[doc = edoc!(checkerr(Self))]
152 PartMap {
153 /// The [`UrlPart`] to index [`Self::PartMap::map`] with.
154 part: UrlPart,
155 /// The [`Map`] to index with [`Self::PartMap::part`].
156 #[serde(flatten)]
157 map: Map<Self>
158 },
159 /// Gets the string specified by [`Self::StringMap::value`], indexes [`Self::StringMap::map`], and returns the value of the returned [`Self`].
160 ///
161 /// If the call to [`Map::get`] returns [`None`], fails.
162 /// # Errors
163 #[doc = edoc!(geterr(StringSource), checkerr(Self))]
164 StringMap {
165 /// The [`StringSource`] to index [`Self::StringMap::map`] with.
166 value: StringSource,
167 /// The [`Map`] to index with [`Self::StringMap::value`].
168 #[serde(flatten)]
169 map: Map<Self>
170 },
171 /// Gets the name of the partition [`Self::PartNamedPartitioning::part`] is in in the specified [`NamedPartitioning`], indexes [`Self::PartNamedPartitioning::map`] with the partition name, and if the [`Map`] has a [`Self`] there, applies it.
172 /// # Errors
173 #[doc = edoc!(geterr(StringSource, 2), getnone(StringSource, Condition, 2), notfound(NamedPartitioning, Condition), checkerr(Self))]
174 PartNamedPartitioning {
175 /// The [`NamedPartitioning`] to search in.
176 named_partitioning: StringSource,
177 /// The [`UrlPart`] whose value to find in the [`NamedPartitioning`].
178 part: UrlPart,
179 /// The [`Map`] to index.
180 #[serde(flatten)]
181 map: Map<Self>
182 },
183 /// Gets the name of the partition [`Self::StringNamedPartitioning::value`] is in in the specified [`NamedPartitioning`], indexes [`Self::StringNamedPartitioning::map`] with the partition name, and if the [`Map`] has a [`Self`] there, applies it.
184 /// # Errors
185 #[doc = edoc!(geterr(StringSource), getnone(StringSource, Condition), notfound(NamedPartitioning, Condition), checkerr(Self))]
186 StringNamedPartitioning {
187 /// The [`NamedPartitioning`] to search in.
188 named_partitioning: StringSource,
189 /// The [`StringSource`] whose value to find in the [`NamedPartitioning`].
190 value: StringSource,
191 /// The [`Map`] to index.
192 #[serde(flatten)]
193 map: Map<Self>
194 },
195
196 // Params
197
198 /// Satisfied if the specified flag is set.
199 /// # Errors
200 #[doc = edoc!(geterr(FlagRef))]
201 FlagIsSet(FlagRef),
202 /// Satisfied if the specified flag is not set.
203 /// # Errors
204 #[doc = edoc!(geterr(FlagRef))]
205 FlagIsNotSet(FlagRef),
206 /// Satisfied if [`Self::VarIs::var`] is [`Self::VarIs::value`].
207 /// # Errors
208 #[doc = edoc!(geterr(VarRef), geterr(StringSource))]
209 VarIs {
210 /// The var to check the value of.
211 #[serde(flatten)]
212 var: VarRef,
213 /// The value to check if [`Self::VarIs::var`] is.
214 value: StringSource
215 },
216
217 // String source
218
219 /// Satisfied if [`Self::StringIs::left`] is [`Self::StringIs::right`].
220 /// # Errors
221 #[doc = edoc!(geterr(StringSource, 2))]
222 /// # Examples
223 /// ```
224 /// use url_cleaner_engine::types::*;
225 ///
226 /// url_cleaner_engine::task_state_view!(task_state);
227 ///
228 /// assert!( Condition::StringIs {left: "a".into(), right: "a".into()}.check(&task_state).unwrap());
229 /// assert!(!Condition::StringIs {left: "a".into(), right: "b".into()}.check(&task_state).unwrap());
230 /// ```
231 StringIs {
232 /// The left hand side of the equality check.
233 left: StringSource,
234 /// The right hand side of the equality check.
235 right: StringSource
236 },
237 /// Satisfied if the specified [`StringSource`] is [`Some`].
238 /// # Errors
239 #[doc = edoc!(geterr(StringSource))]
240 /// # Examples
241 /// ```
242 /// use url_cleaner_engine::types::*;
243 ///
244 /// url_cleaner_engine::task_state_view!(task_state);
245 ///
246 /// assert!( Condition::StringIsSome("abc" .into()).check(&task_state).unwrap());
247 /// assert!(!Condition::StringIsSome(None::<&str>.into()).check(&task_state).unwrap());
248 /// ```
249 StringIsSome(StringSource),
250 /// Satisfied if [`Self::StringContains::value`] contains [`Self::StringContains::substring`] at [`Self::StringContains::value`].
251 /// # Errors
252 #[doc = edoc!(geterr(StringSource), getnone(StringSource, Condition), checkerr(StringLocation))]
253 /// # Examples
254 /// ```
255 /// use url_cleaner_engine::types::*;
256 ///
257 /// url_cleaner_engine::task_state_view!(task_state);
258 ///
259 /// assert!(Condition::StringContains {value: "abc".into(), substring: "b".into(), at: StringLocation::Anywhere}.check(&task_state).unwrap());
260 /// ```
261 StringContains {
262 /// The value to search for [`Self::StringContains::substring`].
263 value: StringSource,
264 /// The value to search for inside [`Self::StringContains::value`].
265 substring: StringSource,
266 /// Where in [`Self::StringContains::value`] to search for [`Self::StringContains::substring`].
267 ///
268 /// Defaults to [`StringLocation::Anywhere`].
269 #[serde(default, skip_serializing_if = "is_default")]
270 at: StringLocation
271 },
272 /// Satisfied if [`Self::StringMatches::value`] satisfies [`Self::StringMatches::matcher`].
273 /// # Errors
274 #[doc = edoc!(geterr(StringSource), getnone(StringSource, Condition), checkerr(StringMatcher))]
275 /// # Examples
276 /// ```
277 /// use url_cleaner_engine::types::*;
278 ///
279 /// url_cleaner_engine::task_state_view!(task_state);
280 ///
281 /// assert!(Condition::StringMatches {value: "abc".into(), matcher: StringMatcher::Always}.check(&task_state).unwrap());
282 /// ```
283 StringMatches {
284 /// The value to check the value of.
285 value: StringSource,
286 /// The matcher to check if [`Self::StringMatches::value`] satisfies.
287 matcher: StringMatcher
288 },
289
290 // Whole
291
292 /// Satisfied if the URL is the specified string.
293 /// # Errors
294 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError))]
295 /// # Examples
296 /// ```
297 /// use url_cleaner_engine::types::*;
298 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com");
299 ///
300 /// assert!(Condition::UrlIs("https://example.com/".into()).check(&task_state).unwrap());
301 /// ```
302 UrlIs(StringSource),
303
304 // Scheme
305
306 /// Satisfied if the value of [`Url::scheme`] is equal to the specified string.
307 /// # Errors
308 #[doc = edoc!(geterr(StringSource))]
309 SchemeIs(StringSource),
310 /// Satisfied if the [`Url::scheme`] is in the specified [`Set`].
311 /// # Examples
312 /// ```
313 /// use url_cleaner_engine::types::*;
314 /// use url_cleaner_engine::task_state_view as tsv;
315 ///
316 /// let condition = Condition::SchemeIsOneOf(
317 /// [
318 /// "http".to_string(),
319 /// "https".to_string()
320 /// ].into()
321 /// );
322 ///
323 /// tsv!(ts, url = "http://example.com" ); assert!( condition.check(&ts).unwrap());
324 /// tsv!(ts, url = "https://example.com"); assert!( condition.check(&ts).unwrap());
325 /// tsv!(ts, url = "other://example.com"); assert!(!condition.check(&ts).unwrap());
326 /// ```
327 SchemeIsOneOf(Set<String>),
328 /// Satisfied if the [`Url::scheme`] is in the specified [`Params::sets`] [`Set`].
329 /// # Errors
330 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
331 SchemeIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
332
333 // Host is
334
335 /// Satisfied if the value of [`Url::host`] is equal to the specified string.
336 /// # Errors
337 #[doc = edoc!(geterr(StringSource))]
338 /// # Examples
339 /// ```
340 /// use url_cleaner_engine::types::*;
341 /// use url_cleaner_engine::task_state_view as tsv;
342 ///
343 /// let condition = Condition::HostIs("example.com".into());
344 ///
345 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
346 /// tsv!(ts, url = "https://example.com." ); assert!(!condition.check(&ts).unwrap());
347 /// tsv!(ts, url = "https://www.example.com" ); assert!(!condition.check(&ts).unwrap());
348 /// tsv!(ts, url = "https://www.example.com."); assert!(!condition.check(&ts).unwrap());
349 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!condition.check(&ts).unwrap());
350 /// tsv!(ts, url = "https://abc.example.com."); assert!(!condition.check(&ts).unwrap());
351 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
352 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
353 /// ```
354 HostIs(StringSource),
355 /// Satisfied if the [`BetterUrl::normalized_host`] is equal to the specified string.
356 /// # Errors
357 #[doc = edoc!(geterr(StringSource))]
358 /// # Examples
359 /// ```
360 /// use url_cleaner_engine::types::*;
361 /// use url_cleaner_engine::task_state_view as tsv;
362 ///
363 /// let condition = Condition::NormalizedHostIs("example.com".into());
364 ///
365 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
366 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
367 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
368 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
369 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!condition.check(&ts).unwrap());
370 /// tsv!(ts, url = "https://abc.example.com."); assert!(!condition.check(&ts).unwrap());
371 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
372 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
373 /// ```
374 NormalizedHostIs(StringSource),
375 /// Satisfied if the value of [`BetterUrl::subdomain`] is equal to the specified string.
376 /// # Errors
377 #[doc = edoc!(geterr(StringSource))]
378 /// # Examples
379 /// ```
380 /// use url_cleaner_engine::types::*;
381 /// use url_cleaner_engine::task_state_view as tsv;
382 ///
383 /// let condition = Condition::SubdomainIs("www".into());
384 ///
385 /// tsv!(ts, url = "https://example.com" ); assert!(!condition.check(&ts).unwrap());
386 /// tsv!(ts, url = "https://example.com." ); assert!(!condition.check(&ts).unwrap());
387 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
388 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
389 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!condition.check(&ts).unwrap());
390 /// tsv!(ts, url = "https://abc.example.com."); assert!(!condition.check(&ts).unwrap());
391 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
392 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
393 /// ```
394 SubdomainIs(StringSource),
395 /// Satisfied if the value of [`BetterUrl::reg_domain`] is equal to the specified string.
396 /// # Errors
397 #[doc = edoc!(geterr(StringSource))]
398 /// # Examples
399 /// ```
400 /// use url_cleaner_engine::types::*;
401 /// use url_cleaner_engine::task_state_view as tsv;
402 ///
403 /// let condition = Condition::RegDomainIs("example.com".into());
404 ///
405 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
406 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
407 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
408 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
409 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
410 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
411 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
412 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
413 /// ```
414 RegDomainIs(StringSource),
415 /// Satisfied if the value of [`BetterUrl::domain`] is equal to the specified string.
416 /// # Errors
417 #[doc = edoc!(geterr(StringSource))]
418 /// # Examples
419 /// ```
420 /// use url_cleaner_engine::types::*;
421 /// use url_cleaner_engine::task_state_view as tsv;
422 ///
423 /// let condition = Condition::DomainIs("example.com".into());
424 ///
425 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
426 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
427 /// tsv!(ts, url = "https://www.example.com" ); assert!(!condition.check(&ts).unwrap());
428 /// tsv!(ts, url = "https://www.example.com."); assert!(!condition.check(&ts).unwrap());
429 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!condition.check(&ts).unwrap());
430 /// tsv!(ts, url = "https://abc.example.com."); assert!(!condition.check(&ts).unwrap());
431 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
432 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
433 /// ```
434 DomainIs(StringSource),
435 /// Satisfied if the value of [`BetterUrl::domain_middle`] is equal to the specified string.
436 /// # Errors
437 #[doc = edoc!(geterr(StringSource))]
438 /// # Examples
439 /// ```
440 /// use url_cleaner_engine::types::*;
441 /// use url_cleaner_engine::task_state_view as tsv;
442 ///
443 /// let condition = Condition::DomainMiddleIs("example".into());
444 ///
445 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
446 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
447 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
448 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
449 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
450 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
451 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
452 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
453 /// ```
454 DomainMiddleIs(StringSource),
455 /// Satisfied if the value of [`BetterUrl::not_domain_suffix`] is equal to the specified string.
456 /// # Errors
457 #[doc = edoc!(geterr(StringSource))]
458 /// # Examples
459 /// ```
460 /// use url_cleaner_engine::types::*;
461 /// use url_cleaner_engine::task_state_view as tsv;
462 ///
463 /// let condition = Condition::NotDomainSuffixIs("www.example".into());
464 ///
465 /// tsv!(ts, url = "https://example.com" ); assert!(!condition.check(&ts).unwrap());
466 /// tsv!(ts, url = "https://example.com." ); assert!(!condition.check(&ts).unwrap());
467 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
468 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
469 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!condition.check(&ts).unwrap());
470 /// tsv!(ts, url = "https://abc.example.com."); assert!(!condition.check(&ts).unwrap());
471 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
472 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
473 /// ```
474 NotDomainSuffixIs(StringSource),
475 /// Satisfied if the value of [`BetterUrl::domain_suffix`] is equal to the specified string.
476 /// # Errors
477 #[doc = edoc!(geterr(StringSource))]
478 /// # Examples
479 /// ```
480 /// use url_cleaner_engine::types::*;
481 /// use url_cleaner_engine::task_state_view as tsv;
482 ///
483 /// let condition = Condition::DomainSuffixIs("com".into());
484 ///
485 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
486 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
487 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
488 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
489 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
490 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
491 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
492 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
493 /// ```
494 DomainSuffixIs(StringSource),
495
496
497
498 /// Satisfied if the [`BetterUrl::subdomain_segment`] is the specified value.
499 /// # Errors
500 #[doc = edoc!(geterr(StringSource))]
501 SubdomainSegmentIs {
502 /// The segment to check.
503 index: isize,
504 /// The value to compare it to.
505 value: StringSource
506 },
507 /// Satisfied if the [`BetterUrl::domain_segment`] is the specified value.
508 /// # Errors
509 #[doc = edoc!(geterr(StringSource))]
510 DomainSegmentIs {
511 /// The segment to check.
512 index: isize,
513 /// The value to compare it to.
514 value: StringSource
515 },
516 /// Satisfied if the [`BetterUrl::domain_suffix_segment`] is the specified value.
517 /// # Errors
518 #[doc = edoc!(geterr(StringSource))]
519 DomainSuffixSegmentIs {
520 /// The segment to check.
521 index: isize,
522 /// The value to compare it to.
523 value: StringSource
524 },
525
526 // Host is one of
527
528 /// Satisfied if the [`Url::host`] is contained in the specified [`Set`].
529 /// # Examples
530 /// ```
531 /// use url_cleaner_engine::types::*;
532 /// use url_cleaner_engine::task_state_view as tsv;
533 ///
534 /// let condition = Condition::HostIsOneOf(
535 /// [
536 /// "example.com".to_string(),
537 /// "www.example.com".to_string()
538 /// ].into()
539 /// );
540 ///
541 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
542 /// tsv!(ts, url = "https://example.com." ); assert!(!condition.check(&ts).unwrap());
543 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
544 /// tsv!(ts, url = "https://www.example.com."); assert!(!condition.check(&ts).unwrap());
545 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!condition.check(&ts).unwrap());
546 /// tsv!(ts, url = "https://abc.example.com."); assert!(!condition.check(&ts).unwrap());
547 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
548 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
549 /// ```
550 HostIsOneOf(Set<String>),
551 /// Satisfied if the [`BetterUrl::normalized_host`] is in the specified [`Set`].
552 /// # Examples
553 /// ```
554 /// use url_cleaner_engine::types::*;
555 /// use url_cleaner_engine::task_state_view as tsv;
556 ///
557 /// let condition = Condition::NormalizedHostIsOneOf(
558 /// [
559 /// "example.com".to_string()
560 /// ].into()
561 /// );
562 ///
563 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
564 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
565 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
566 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
567 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!condition.check(&ts).unwrap());
568 /// tsv!(ts, url = "https://abc.example.com."); assert!(!condition.check(&ts).unwrap());
569 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
570 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
571 /// ```
572 NormalizedHostIsOneOf(Set<String>),
573 /// Satisfied if the [`BetterUrl::subdomain`] is contained in the specified [`Set`].
574 /// # Examples
575 /// ```
576 /// use url_cleaner_engine::types::*;
577 /// use url_cleaner_engine::task_state_view as tsv;
578 ///
579 /// let condition = Condition::SubdomainIsOneOf(
580 /// [
581 /// "www".to_string(),
582 /// "abc".to_string()
583 /// ].into()
584 /// );
585 ///
586 /// tsv!(ts, url = "https://example.com" ); assert!(!condition.check(&ts).unwrap());
587 /// tsv!(ts, url = "https://example.com." ); assert!(!condition.check(&ts).unwrap());
588 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
589 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
590 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
591 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
592 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
593 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
594 /// ```
595 SubdomainIsOneOf(Set<String>),
596 /// Satisfied if the [`BetterUrl::reg_domain`] is in the specified [`Set`].
597 /// # Examples
598 /// ```
599 /// use url_cleaner_engine::types::*;
600 /// use url_cleaner_engine::task_state_view as tsv;
601 ///
602 /// let condition = Condition::RegDomainIsOneOf(
603 /// [
604 /// "example.com".to_string()
605 /// ].into()
606 /// );
607 ///
608 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
609 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
610 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
611 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
612 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
613 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
614 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
615 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
616 /// ```
617 RegDomainIsOneOf(Set<String>),
618 /// Satisfied if the [`BetterUrl::domain`] is in the specified [`Set`].
619 /// # Examples
620 /// ```
621 /// use url_cleaner_engine::types::*;
622 /// use url_cleaner_engine::task_state_view as tsv;
623 ///
624 /// let condition = Condition::DomainIsOneOf(
625 /// [
626 /// "example.com".to_string(),
627 /// "abc.example.com".to_string()
628 /// ].into()
629 /// );
630 ///
631 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
632 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
633 /// tsv!(ts, url = "https://www.example.com" ); assert!(!condition.check(&ts).unwrap());
634 /// tsv!(ts, url = "https://www.example.com."); assert!(!condition.check(&ts).unwrap());
635 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
636 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
637 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
638 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
639 /// ```
640 DomainIsOneOf(Set<String>),
641 /// Satisfied if the [`BetterUrl::domain_middle`] is in the specified [`Set`].
642 /// # Examples
643 /// ```
644 /// use url_cleaner_engine::types::*;
645 /// use url_cleaner_engine::task_state_view as tsv;
646 ///
647 /// let condition = Condition::DomainMiddleIsOneOf(
648 /// [
649 /// "example".to_string()
650 /// ].into()
651 /// );
652 ///
653 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
654 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
655 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
656 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
657 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
658 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
659 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
660 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
661 /// ```
662 DomainMiddleIsOneOf(Set<String>),
663 /// Satisfied if the [`BetterUrl::not_domain_suffix`] is in the specified [`Set`].
664 /// # Examples
665 /// ```
666 /// use url_cleaner_engine::types::*;
667 /// use url_cleaner_engine::task_state_view as tsv;
668 ///
669 /// let condition = Condition::NotDomainSuffixIsOneOf(
670 /// [
671 /// "example".to_string(),
672 /// "abc.example".to_string()
673 /// ].into()
674 /// );
675 ///
676 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
677 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
678 /// tsv!(ts, url = "https://www.example.com" ); assert!(!condition.check(&ts).unwrap());
679 /// tsv!(ts, url = "https://www.example.com."); assert!(!condition.check(&ts).unwrap());
680 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
681 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
682 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
683 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
684 /// ```
685 NotDomainSuffixIsOneOf(Set<String>),
686 /// Satisfied if the [`BetterUrl::domain_suffix`] is in the specified [`Set`].
687 /// # Examples
688 /// ```
689 /// use url_cleaner_engine::types::*;
690 /// use url_cleaner_engine::task_state_view as tsv;
691 ///
692 /// let condition = Condition::DomainSuffixIsOneOf(
693 /// [
694 /// "com".to_string()
695 /// ].into()
696 /// );
697 ///
698 /// tsv!(ts, url = "https://example.com" ); assert!( condition.check(&ts).unwrap());
699 /// tsv!(ts, url = "https://example.com." ); assert!( condition.check(&ts).unwrap());
700 /// tsv!(ts, url = "https://www.example.com" ); assert!( condition.check(&ts).unwrap());
701 /// tsv!(ts, url = "https://www.example.com."); assert!( condition.check(&ts).unwrap());
702 /// tsv!(ts, url = "https://abc.example.com" ); assert!( condition.check(&ts).unwrap());
703 /// tsv!(ts, url = "https://abc.example.com."); assert!( condition.check(&ts).unwrap());
704 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!condition.check(&ts).unwrap());
705 /// tsv!(ts, url = "https://[::1]" ); assert!(!condition.check(&ts).unwrap());
706 /// ```
707 DomainSuffixIsOneOf(Set<String>),
708
709
710
711 /// Satisfied if the [`BetterUrl::subdomain_segment`] is in the specified [`Set`].
712 SubdomainSegmentIsOneOf {
713 /// The segment to check.
714 index: isize,
715 /// The set to check it with.
716 values: Set<String>
717 },
718 /// Satisfied if the [`BetterUrl::domain_segment`] is in the specified [`Set`].
719 DomainSegmentIsOneOf {
720 /// The segment to check.
721 index: isize,
722 /// The set to check it with.
723 values: Set<String>
724 },
725 /// Satisfied if the [`BetterUrl::domain_suffix_segment`] is in the specified [`Set`].
726 DomainSuffixSegmentIsOneOf {
727 /// The segment to check.
728 index: isize,
729 /// The set to check it with.
730 values: Set<String>
731 },
732
733 // Host is in set
734
735 /// Satisfied if the [`Url::host_str`] is in the specified [`Params::sets`] [`Set`].
736 /// # Errors
737 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
738 HostIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
739 /// Satisfied if the [`BetterUrl::normalized_host`] is in the specified [`Params::sets`] [`Set`].
740 /// # Errors
741 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
742 NormalizedHostIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
743 /// Satisfied if the [`BetterUrl::subdomain`] is in the specified [`Params::sets`] [`Set`].
744 /// # Errors
745 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
746 SubdomainIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
747 /// Satisfied if the [`BetterUrl::reg_domain`] is in the specified [`Params::sets`] [`Set`].
748 /// # Errors
749 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
750 RegDomainIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
751 /// Satisfied if the [`BetterUrl::domain`] is in the specified [`Params::sets`] [`Set`].
752 /// # Errors
753 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
754 DomainIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
755 /// Satisfied if the [`BetterUrl::domain_middle`] is in the specified [`Params::sets`] [`Set`].
756 /// # Errors
757 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
758 DomainMiddleIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
759 /// Satisfied if the [`BetterUrl::not_domain_suffix`] is in the specified [`Params::sets`] [`Set`].
760 /// # Errors
761 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
762 NotDomainSuffixIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
763 /// Satisfied if the [`BetterUrl::domain_suffix`] is in the specified [`Params::sets`] [`Set`].
764 /// # Errors
765 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
766 DomainSuffixIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
767
768
769
770 /// Satisfied if the [`BetterUrl::subdomain_segment`] is in the specified [`Params::sets`] [`Set`].
771 /// # Errors
772 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
773 SubdomainSegmentIsInSet {
774 /// The segment to check.
775 index: isize,
776 /// The name of the [`Params::sets`] [`Set`] to check it with.
777 #[suitable(assert = "set_is_documented")]
778 set: StringSource
779 },
780 /// Satisfied if the [`BetterUrl::domain_segment`] is in the specified [`Params::sets`] [`Set`].
781 /// # Errors
782 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
783 DomainSegmentIsInSet {
784 /// The segment to check.
785 index: isize,
786 /// The name of the [`Params::sets`] [`Set`] to check it with.
787 #[suitable(assert = "set_is_documented")]
788 set: StringSource
789 },
790 /// Satisfied if the [`BetterUrl::domain_suffix_segment`] is in the specified [`Params::sets`] [`Set`].
791 /// # Errors
792 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
793 DomainSuffixSegmentIsInSet {
794 /// The segment to check.
795 index: isize,
796 /// The name of the [`Params::sets`] [`Set`] to check it with.
797 #[suitable(assert = "set_is_documented")]
798 set: StringSource
799 },
800
801 // Misc. host
802
803 /// Satisfied if the [`Url::host`] is [`Some`].
804 /// # Examples
805 /// ```
806 /// use url_cleaner_engine::types::*;
807 /// use url_cleaner_engine::task_state_view as tsv;
808 ///
809 /// tsv!(ts, url = "https://example.com" ); assert!(Condition::UrlHasHost.check(&ts).unwrap());
810 /// tsv!(ts, url = "https://example.com." ); assert!(Condition::UrlHasHost.check(&ts).unwrap());
811 /// tsv!(ts, url = "https://www.example.com" ); assert!(Condition::UrlHasHost.check(&ts).unwrap());
812 /// tsv!(ts, url = "https://www.example.com."); assert!(Condition::UrlHasHost.check(&ts).unwrap());
813 /// tsv!(ts, url = "https://abc.example.com" ); assert!(Condition::UrlHasHost.check(&ts).unwrap());
814 /// tsv!(ts, url = "https://abc.example.com."); assert!(Condition::UrlHasHost.check(&ts).unwrap());
815 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(Condition::UrlHasHost.check(&ts).unwrap());
816 /// tsv!(ts, url = "https://[::1]" ); assert!(Condition::UrlHasHost.check(&ts).unwrap());
817 /// ```
818 UrlHasHost,
819 /// Satisfied if the URL's host is a fully qualified domain name.
820 /// # Examples
821 /// ```
822 /// use url_cleaner_engine::types::*;
823 /// use url_cleaner_engine::task_state_view as tsv;
824 ///
825 /// tsv!(ts, url = "https://example.com" ); assert!(!Condition::HostIsFqdn.check(&ts).unwrap());
826 /// tsv!(ts, url = "https://example.com." ); assert!( Condition::HostIsFqdn.check(&ts).unwrap());
827 /// tsv!(ts, url = "https://www.example.com" ); assert!(!Condition::HostIsFqdn.check(&ts).unwrap());
828 /// tsv!(ts, url = "https://www.example.com."); assert!( Condition::HostIsFqdn.check(&ts).unwrap());
829 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!Condition::HostIsFqdn.check(&ts).unwrap());
830 /// tsv!(ts, url = "https://abc.example.com."); assert!( Condition::HostIsFqdn.check(&ts).unwrap());
831 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!Condition::HostIsFqdn.check(&ts).unwrap());
832 /// tsv!(ts, url = "https://[::1]" ); assert!(!Condition::HostIsFqdn.check(&ts).unwrap());
833 /// ```
834 HostIsFqdn,
835 /// Satisfied if the URL's host is a domain.
836 /// # Examples
837 /// ```
838 /// use url_cleaner_engine::types::*;
839 /// use url_cleaner_engine::task_state_view as tsv;
840 ///
841 /// tsv!(ts, url = "https://example.com" ); assert!( Condition::HostIsDomain.check(&ts).unwrap());
842 /// tsv!(ts, url = "https://example.com." ); assert!( Condition::HostIsDomain.check(&ts).unwrap());
843 /// tsv!(ts, url = "https://www.example.com" ); assert!( Condition::HostIsDomain.check(&ts).unwrap());
844 /// tsv!(ts, url = "https://www.example.com."); assert!( Condition::HostIsDomain.check(&ts).unwrap());
845 /// tsv!(ts, url = "https://abc.example.com" ); assert!( Condition::HostIsDomain.check(&ts).unwrap());
846 /// tsv!(ts, url = "https://abc.example.com."); assert!( Condition::HostIsDomain.check(&ts).unwrap());
847 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!Condition::HostIsDomain.check(&ts).unwrap());
848 /// tsv!(ts, url = "https://[::1]" ); assert!(!Condition::HostIsDomain.check(&ts).unwrap());
849 /// ```
850 HostIsDomain,
851 /// Satisfied if the URL's host is an IP address.
852 /// # Examples
853 /// ```
854 /// use url_cleaner_engine::types::*;
855 /// use url_cleaner_engine::task_state_view as tsv;
856 ///
857 /// tsv!(ts, url = "https://example.com" ); assert!(!Condition::HostIsIp.check(&ts).unwrap());
858 /// tsv!(ts, url = "https://example.com." ); assert!(!Condition::HostIsIp.check(&ts).unwrap());
859 /// tsv!(ts, url = "https://www.example.com" ); assert!(!Condition::HostIsIp.check(&ts).unwrap());
860 /// tsv!(ts, url = "https://www.example.com."); assert!(!Condition::HostIsIp.check(&ts).unwrap());
861 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!Condition::HostIsIp.check(&ts).unwrap());
862 /// tsv!(ts, url = "https://abc.example.com."); assert!(!Condition::HostIsIp.check(&ts).unwrap());
863 /// tsv!(ts, url = "https://127.0.0.1" ); assert!( Condition::HostIsIp.check(&ts).unwrap());
864 /// tsv!(ts, url = "https://[::1]" ); assert!( Condition::HostIsIp.check(&ts).unwrap());
865 /// ```
866 HostIsIp,
867 /// Satisfied if the URL's host is an IPv4 address.
868 /// # Examples
869 /// ```
870 /// use url_cleaner_engine::types::*;
871 /// use url_cleaner_engine::task_state_view as tsv;
872 ///
873 /// tsv!(ts, url = "https://example.com" ); assert!(!Condition::HostIsIpv4.check(&ts).unwrap());
874 /// tsv!(ts, url = "https://example.com." ); assert!(!Condition::HostIsIpv4.check(&ts).unwrap());
875 /// tsv!(ts, url = "https://www.example.com" ); assert!(!Condition::HostIsIpv4.check(&ts).unwrap());
876 /// tsv!(ts, url = "https://www.example.com."); assert!(!Condition::HostIsIpv4.check(&ts).unwrap());
877 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!Condition::HostIsIpv4.check(&ts).unwrap());
878 /// tsv!(ts, url = "https://abc.example.com."); assert!(!Condition::HostIsIpv4.check(&ts).unwrap());
879 /// tsv!(ts, url = "https://127.0.0.1" ); assert!( Condition::HostIsIpv4.check(&ts).unwrap());
880 /// tsv!(ts, url = "https://[::1]" ); assert!(!Condition::HostIsIpv4.check(&ts).unwrap());
881 /// ```
882 HostIsIpv4,
883 /// Satisfied if the URL's host is an IPv6 address.
884 /// # Examples
885 /// ```
886 /// use url_cleaner_engine::types::*;
887 /// use url_cleaner_engine::task_state_view as tsv;
888 ///
889 /// tsv!(ts, url = "https://example.com" ); assert!(!Condition::HostIsIpv6.check(&ts).unwrap());
890 /// tsv!(ts, url = "https://example.com." ); assert!(!Condition::HostIsIpv6.check(&ts).unwrap());
891 /// tsv!(ts, url = "https://www.example.com" ); assert!(!Condition::HostIsIpv6.check(&ts).unwrap());
892 /// tsv!(ts, url = "https://www.example.com."); assert!(!Condition::HostIsIpv6.check(&ts).unwrap());
893 /// tsv!(ts, url = "https://abc.example.com" ); assert!(!Condition::HostIsIpv6.check(&ts).unwrap());
894 /// tsv!(ts, url = "https://abc.example.com."); assert!(!Condition::HostIsIpv6.check(&ts).unwrap());
895 /// tsv!(ts, url = "https://127.0.0.1" ); assert!(!Condition::HostIsIpv6.check(&ts).unwrap());
896 /// tsv!(ts, url = "https://[::1]" ); assert!( Condition::HostIsIpv6.check(&ts).unwrap());
897 /// ```
898 HostIsIpv6,
899
900 // Path
901
902 /// Satisfied if the [`Url::path`] is the specified value.
903 /// # Examples
904 /// ```
905 /// use url_cleaner_engine::types::*;
906 ///
907 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com/a/b/c");
908 /// assert!( Condition::PathIs("/a/b/c" .into()).check(&task_state).unwrap());
909 /// assert!(!Condition::PathIs("/a/b/c/".into()).check(&task_state).unwrap());
910 /// ```
911 PathIs(StringSource),
912 /// Satisfied if the [`Url::path`] is in the specified [`Set`].
913 PathIsOneOf(Set<String>),
914 /// Satisfied if the [`Url::path`] is in the specified [`Params::sets`] [`Set`].
915 /// # Errors
916 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
917 PathIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
918 /// Satisfied if the [`Url::path`] starts with the specified value.
919 /// # Examples
920 /// ```
921 /// use url_cleaner_engine::types::*;
922 ///
923 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com/a/b/c");
924 /// assert!( Condition::PathStartsWith("" .into()).check(&task_state).unwrap());
925 /// assert!( Condition::PathStartsWith("/" .into()).check(&task_state).unwrap());
926 /// assert!( Condition::PathStartsWith("/a" .into()).check(&task_state).unwrap());
927 /// assert!( Condition::PathStartsWith("/a/" .into()).check(&task_state).unwrap());
928 /// assert!( Condition::PathStartsWith("/a/b" .into()).check(&task_state).unwrap());
929 /// assert!( Condition::PathStartsWith("/a/b/" .into()).check(&task_state).unwrap());
930 /// assert!( Condition::PathStartsWith("/a/b/c" .into()).check(&task_state).unwrap());
931 /// assert!(!Condition::PathStartsWith("/a/b/c/" .into()).check(&task_state).unwrap());
932 /// assert!(!Condition::PathStartsWith("/a/b/c/d".into()).check(&task_state).unwrap());
933 /// ```
934 PathStartsWith(StringSource),
935 /// # Errors
936 #[doc = edoc!(callerr(BetterUrl::first_n_path_segments), geterr(StringSource))]
937 FirstNPathSegmentsIs {
938 /// The number of path segments to get.
939 n: usize,
940 /// The value to check if it's equal to.
941 value: StringSource
942 },
943 /// # Errors
944 #[doc = edoc!(callerr(BetterUrl::first_n_path_segments))]
945 FirstNPathSegmentsIsOneOf {
946 /// The number of path segments to get.
947 n: usize,
948 /// The [`Set`] to check if it's in.
949 set: Set<String>
950 },
951 /// # Errors
952 #[doc = edoc!(callerr(BetterUrl::first_n_path_segments), geterr(StringSource), notfound(Set, Condition))]
953 FirstNPathSegmentsIsInSet {
954 /// The number of path segments to get.
955 n: usize,
956 /// The name of the [`Params::sets`] [`Set`] to check if it's in.
957 set: StringSource
958 },
959 /// # Errors
960 #[doc = edoc!(callerr(BetterUrl::last_n_path_segments), geterr(StringSource))]
961 LastNPathSegmentsIs {
962 /// The number of path segments to get.
963 n: usize,
964 /// The value to check if it's equal to.
965 value: StringSource
966 },
967 /// # Errors
968 #[doc = edoc!(callerr(BetterUrl::last_n_path_segments))]
969 LastNPathSegmentsIsOneOf {
970 /// The number of path segments to get.
971 n: usize,
972 /// The [`Set`] to check if it's in.
973 set: Set<String>
974 },
975 /// # Errors
976 #[doc = edoc!(callerr(BetterUrl::last_n_path_segments), geterr(StringSource), notfound(Set, Condition))]
977 LastNPathSegmentsIsInSet {
978 /// The number of path segments to get.
979 n: usize,
980 /// The name of the [`Params::sets`] [`Set`] to check if it's in.
981 set: StringSource
982 },
983
984
985
986 /// Satisfied if the [`Url::path`] has segments.
987 PathHasSegments,
988 /// Satisfied if the call to [`BetterUrl::path_segment`] returns [`Ok`] of [`Some`].
989 ///
990 /// Unsatisfied if [`BetterUrl::path_segment`] returns [`Err`] because not having path segments means it doesn't have the specified path segment.
991 HasPathSegment(isize),
992 /// Satisfied if the [`BetterUrl::path_segment`] is the specified value.
993 /// # Errors
994 #[doc = edoc!(callerr(BetterUrl::path_segment))]
995 PathSegmentIs {
996 /// The segment to check.
997 index: isize,
998 /// The value to compare it to.
999 value: StringSource
1000 },
1001 /// Satisfied if the [`BetterUrl::path_segment`] is in the specified [`Set`].
1002 /// # Errors
1003 #[doc = edoc!(callerr(BetterUrl::path_segment))]
1004 PathSegmentIsOneOf {
1005 /// The segment to check.
1006 index: isize,
1007 /// The set to check it with.
1008 values: Set<String>
1009 },
1010 /// Satisfied if the [`BetterUrl::path_segment`] is in the specified [`Params::sets`] [`Set`].
1011 /// # Errors
1012 #[doc = edoc!(callerr(BetterUrl::path_segment), geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
1013 PathSegmentIsInSet {
1014 /// The segment to check.
1015 index: isize,
1016 /// The name of the [`Params::sets`] [`Set`] to check it with.
1017 #[suitable(assert = "set_is_documented")]
1018 set: StringSource
1019 },
1020
1021 // Query
1022
1023 /// Satisfied if the [`Url::query`] is the specified value.
1024 QueryIs(StringSource),
1025 /// Satisfied if the URL' has a query query and has a matching query parameter.
1026 /// # Examples
1027 /// ```
1028 /// use url_cleaner_engine::types::*;
1029 ///
1030 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com?a=2&b=3");
1031 /// assert!( Condition::HasQueryParam("a".into()).check(&task_state).unwrap());
1032 /// assert!( Condition::HasQueryParam("b".into()).check(&task_state).unwrap());
1033 /// assert!(!Condition::HasQueryParam("c".into()).check(&task_state).unwrap());
1034 /// ```
1035 HasQueryParam(QueryParamSelector),
1036 /// Satisfied if the [`BetterUrl::query_param`] is the specified value.
1037 QueryParamIs {
1038 /// The query param to check.
1039 param: QueryParamSelector,
1040 /// The value to compare it to.
1041 value: StringSource
1042 },
1043 /// Satisfied if the [`BetterUrl::query_param`] is in the specified [`Set`].
1044 QueryParamIsOneOf {
1045 /// The query param to check.
1046 param: QueryParamSelector,
1047 /// The set to check it with.
1048 values: Set<String>
1049 },
1050 /// Satisfied if the [`BetterUrl::query_param`] is in the specified [`Params::sets`] [`Set`].
1051 /// # Errors
1052 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
1053 QueryParamIsInSet {
1054 /// The query param to check.
1055 param: QueryParamSelector,
1056 /// The name of the [`Params::sets`] [`Set`] to check it with.
1057 #[suitable(assert = "set_is_documented")]
1058 set: StringSource
1059 },
1060
1061 // Fragment
1062
1063 /// Satisfied if the [`Url::fragment`] is the specified value.
1064 FragmentIs(StringSource),
1065 /// Satisfied if the [`Url::fragment`] is in the specified [`Set`].
1066 FragmentIsOneOf(Set<String>),
1067 /// Satisfied if the [`Url::fragment`] is in the specified [`Params::sets`] [`Set`].
1068 /// # Errors
1069 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
1070 FragmentIsInSet(#[suitable(assert = "set_is_documented")] StringSource),
1071 /// Satisfied if the [`Url::fragment`] is [`Some`] and starts with the specified value.
1072 /// # Errors
1073 #[doc = edoc!(geterr(StringSource))]
1074 FragmentIsSomeAndStartsWith(StringSource),
1075
1076 // General parts
1077
1078 /// Satisfied if the value of [`Self::PartIs::part`] is the same as the value of [`Self::PartIs::value`].
1079 /// # Errors
1080 #[doc = edoc!(geterr(StringSource))]
1081 /// # Examples
1082 /// ```
1083 /// use url_cleaner_engine::types::*;
1084 ///
1085 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com/abc?a=2");
1086 /// assert!(Condition::PartIs {part: UrlPart::Host , value: "example.com".into()}.check(&task_state).unwrap());
1087 /// assert!(Condition::PartIs {part: UrlPart::Path , value: "/abc" .into()}.check(&task_state).unwrap());
1088 /// assert!(Condition::PartIs {part: UrlPart::Query , value: "a=2" .into()}.check(&task_state).unwrap());
1089 /// assert!(Condition::PartIs {part: UrlPart::QueryParam("a".into()), value: "2" .into()}.check(&task_state).unwrap());
1090 /// ```
1091 PartIs {
1092 /// The [`UrlPart`] to get.
1093 part: UrlPart,
1094 /// The [`StringSource`] to compare [`Self::PartIs::value`] with.
1095 value: StringSource
1096 },
1097 /// Satisfied if [`Self::PartContains::part`] contains [`Self::PartContains::value`] at [`Self::PartContains::at`].
1098 /// # Errors
1099 #[doc = edoc!(getnone(UrlPart, Condition), getnone(StringSource, Condition), checkerr(StringLocation))]
1100 /// # Examples
1101 /// ```
1102 /// use url_cleaner_engine::types::*;
1103 ///
1104 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com/abc");
1105 ///
1106 /// assert!(Condition::PartContains {part: UrlPart::Path, value: "/ab".into(), at: StringLocation::Start}.check(&task_state).unwrap());
1107 /// Condition::PartContains {part: UrlPart::Fragment, value: "".into(), at: StringLocation::Start}.check(&task_state).unwrap_err();
1108 /// ```
1109 PartContains {
1110 /// The part to look in.
1111 part: UrlPart,
1112 /// The value to look for.
1113 value: StringSource,
1114 /// Where to look in [`Self::PartContains::part`] for [`Self::PartContains::value`].
1115 ///
1116 /// Defaults to [`StringLocation::Anywhere`].
1117 #[serde(default, skip_serializing_if = "is_default")]
1118 at: StringLocation
1119 },
1120 /// Satisfied if [`Self::PartMatches::part`] satisfies [`Self::PartMatches::matcher`].
1121 /// # Errors
1122 #[doc = edoc!(getnone(UrlPart, Condition), checkerr(StringMatcher))]
1123 /// # Examples
1124 /// ```
1125 /// use url_cleaner_engine::types::*;
1126 ///
1127 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com/abc");
1128 ///
1129 /// assert!(Condition::PartMatches {part: UrlPart::Path , matcher: StringMatcher::Always}.check(&task_state).unwrap());
1130 /// assert!(Condition::PartMatches {part: UrlPart::Fragment, matcher: StringMatcher::Always}.check(&task_state).unwrap());
1131 /// ```
1132 PartMatches {
1133 /// The part to match the value of.
1134 part: UrlPart,
1135 /// The matcher to test [`Self::PartMatches::part`] with.
1136 matcher: StringMatcher
1137 },
1138 /// Satisfied if [`Self::PartIsOneOf::part`] is in [`Self::PartIsOneOf::values`].
1139 /// # Examples
1140 /// ```
1141 /// use url_cleaner_engine::types::*;
1142 ///
1143 /// url_cleaner_engine::task_state_view!(task_state, url = "https://example.com/abc");
1144 ///
1145 /// assert!(Condition::PartIsOneOf {part: UrlPart::Path , values: [Some("/abc".into()), None].into()}.check(&task_state).unwrap());
1146 /// assert!(Condition::PartIsOneOf {part: UrlPart::Fragment, values: [Some("/abc".into()), None].into()}.check(&task_state).unwrap());
1147 /// ```
1148 PartIsOneOf {
1149 /// The part to check the value of.
1150 part: UrlPart,
1151 /// The set of values to check if [`Self::PartIsOneOf::part`] is one of.
1152 values: Set<String>
1153 },
1154 /// Satisfied if [`Self::PartIsInSet`] is in the specified [`Params::sets`] [`Set`].
1155 /// # Errors
1156 #[doc = edoc!(geterr(StringSource), getnone(StringSource, ConditionError), notfound(Set, Condition))]
1157 PartIsInSet {
1158 /// The part to check the value of.
1159 part: UrlPart,
1160 /// The name of the [`Params::sets`] [`Set`] to check it with.
1161 #[suitable(assert = "set_is_documented")]
1162 set: StringSource
1163 },
1164
1165 // Misc.
1166
1167 /// Satisfied if the specified [`Self`] from [`TaskStateView::commons`]'s [`Commons::conditions`] is.
1168 /// # Errors
1169 #[doc = edoc!(geterr(StringSource), getnone(StringSource, Condition), commonnotfound(Self, Condition), callerr(CommonCallArgsSource::build), checkerr(Self))]
1170 /// # Examples
1171 /// ```
1172 /// use url_cleaner_engine::types::*;
1173 ///
1174 /// url_cleaner_engine::task_state_view!(task_state, commons = Commons {
1175 /// conditions: [("abc".into(), Condition::Always)].into(),
1176 /// ..Default::default()
1177 /// });
1178 ///
1179 /// assert!(Condition::Common(CommonCall {name: Box::new("abc".into()), args: Default::default()}).check(&task_state).unwrap());
1180 /// ```
1181 Common(CommonCall),
1182 /// Gets a [`Self`] from [`TaskStateView::common_args`]'s [`CommonCallArgs::conditions`] and applies it.
1183 /// # Errors
1184 /// If [`TaskStateView::common_args`] is [`None`], returns the error [`ConditionError::NotInCommonContext`].
1185 ///
1186 #[doc = edoc!(commoncallargnotfound(Self, Condition), checkerr(Self))]
1187 CommonCallArg(StringSource),
1188 /// Calls the specified function and returns its value.
1189 ///
1190 /// Because this uses function pointers, this plays weirdly with [`PartialEq`]/[`Eq`].
1191 /// # Errors
1192 #[doc = edoc!(callerr(Self::Custom::0))]
1193 /// # Examples
1194 /// ```
1195 /// use url_cleaner_engine::types::*;
1196 ///
1197 /// url_cleaner_engine::task_state_view!(task_state);
1198 ///
1199 /// fn some_complex_operation(task_state: &TaskStateView) -> Result<bool, ConditionError> {
1200 /// Ok(true)
1201 /// }
1202 ///
1203 /// assert!(Condition::Custom(some_complex_operation).check(&task_state).unwrap());
1204 /// ```
1205 #[cfg(feature = "custom")]
1206 #[suitable(never)]
1207 #[serde(skip)]
1208 Custom(fn(&TaskStateView) -> Result<bool, ConditionError>)
1209}
1210
1211/// The enum of errors [`Condition::check`] can return.
1212#[derive(Debug, Error)]
1213pub enum ConditionError {
1214 /// Returned when a [`Condition::Error`] is used.
1215 #[error("Explicit error: {0}")]
1216 ExplicitError(String),
1217 /// Returned when both [`Condition`]s in a [`Condition::TryElse`] return errors.
1218 #[error("Both Conditions in a Condition::TryElse returned errors.")]
1219 TryElseError {
1220 /// The error returned by [`Condition::TryElse::try`].
1221 try_error: Box<Self>,
1222 /// The error returned by [`Condition::TryElse::else`].
1223 else_error: Box<Self>
1224 },
1225
1226 /// Returned when a [`StringSource`] returned [`None`] where it has to return [`Some`].
1227 #[error("A StringSource returned None where it had to return Some.")]
1228 StringSourceIsNone,
1229 /// Returned when a [`StringSourceError`] is encountered.
1230 #[error(transparent)]
1231 StringSourceError(#[from] StringSourceError),
1232
1233 /// Returned when a part of the URL is [`None`] where it has to be [`Some`].
1234 #[error("A part of the URL is None where it had to be Some.")]
1235 UrlPartIsNone,
1236 /// Returned when attempting to get more path segments than are available.
1237 #[error("Attempted to get more path segments than were available.")]
1238 NotEnoughPathSegments,
1239 /// Returned when attempting to get a path segment not in a URL.
1240 #[error("Attempted to get a path segment not in the URL.")]
1241 PathSegmentNotFound,
1242
1243 /// Returned when a [`StringMatcherError`] is encountered.
1244 #[error(transparent)]
1245 StringMatcherError(#[from] StringMatcherError),
1246 /// Returned when a [`StringLocationError`] is encountered.
1247 #[error(transparent)]
1248 StringLocationError(#[from] StringLocationError),
1249
1250 /// Returned when a [`GetFlagError`] is encountered.
1251 #[error(transparent)]
1252 GetFlagError(#[from] GetFlagError),
1253 /// Returned when a [`GetVarError`] is encountered.
1254 #[error(transparent)]
1255 GetVarError(#[from] GetVarError),
1256
1257 /// Returned when a [`Set`] wasn't found.
1258 #[error("The requested set wasn't found.")]
1259 SetNotFound,
1260 /// Returned when a [`NamedPartitioning`] with the specified name isn't found.
1261 #[error("A NamedPartitioning with the specified name wasn't found.")]
1262 NamedPartitioningNotFound,
1263
1264 /// Returned when a [`Condition`] with the specified name isn't found in the [`Commons::conditions`].
1265 #[error("A Condition with the specified name wasn't found in the Commons::conditions.")]
1266 CommonConditionNotFound,
1267 /// Returned when a [`CommonCallArgsError`] is encountered.
1268 #[error(transparent)]
1269 CommonCallArgsError(#[from] CommonCallArgsError),
1270
1271 /// Returned when trying to use [`Condition::CommonCallArg`] outside of a common context.
1272 #[error("Tried to use Condition::CommonCallArg outside of a common context.")]
1273 NotInCommonContext,
1274 /// Returned when the [`Condition`] requested from a [`Condition::CommonCallArg`] isn't found.
1275 #[error("The Condition requested from a Condition::CommonCallArg wasn't found.")]
1276 CommonCallArgConditionNotFound,
1277 /// An arbitrary [`std::error::Error`] returned by [`Condition::Custom`].
1278 #[error(transparent)]
1279 #[cfg(feature = "custom")]
1280 Custom(Box<dyn std::error::Error + Send>)
1281}
1282
1283impl Condition {
1284 /// If the specified variant of [`Self`] is satisfied, return [`true`].
1285 ///
1286 /// If the specified variant of [`Self`] is unsatisfied, return [`false`].
1287 /// # Errors
1288 /// See each variant of [`Self`] for when each variant returns an error.
1289 pub fn check(&self, task_state: &TaskStateView) -> Result<bool, ConditionError> {
1290 debug!(Condition::check, self);
1291 Ok(match self {
1292 // Debug/constants
1293
1294 Self::Always => true,
1295 Self::Never => false,
1296 Self::Error(msg) => Err(ConditionError::ExplicitError(msg.clone()))?,
1297 Self::Debug(condition) => {
1298 let is_satisfied = condition.check(task_state);
1299 eprintln!("=== Condition::Debug ===\nCondition: {condition:?}\ntask_state: {task_state:?}\nSatisfied?: {is_satisfied:?}");
1300 is_satisfied?
1301 },
1302
1303 // Logic
1304
1305 Self::If {r#if, then, r#else} => if r#if.check(task_state)? {
1306 then.check(task_state)?
1307 } else if let Some(r#else) = r#else {
1308 r#else.check(task_state)?
1309 } else {
1310 false
1311 },
1312 Self::Not(condition) => !condition.check(task_state)?,
1313 Self::All(conditions) => {
1314 for condition in conditions {
1315 if !condition.check(task_state)? {
1316 return Ok(false);
1317 }
1318 }
1319 true
1320 },
1321 Self::Any(conditions) => {
1322 for condition in conditions {
1323 if condition.check(task_state)? {
1324 return Ok(true);
1325 }
1326 }
1327 false
1328 },
1329
1330 // Error handling
1331
1332 Self::ErrorToSatisfied (condition) => condition.check(task_state).unwrap_or(true),
1333 Self::ErrorToUnsatisfied(condition) => condition.check(task_state).unwrap_or(false),
1334 Self::TryElse{ r#try, r#else } => match r#try.check(task_state) {
1335 Ok(x) => x,
1336 Err(try_error) => match r#else.check(task_state) {
1337 Ok(x) => x,
1338 Err(else_error) => Err(ConditionError::TryElseError {try_error: Box::new(try_error), else_error: Box::new(else_error)})?
1339 }
1340 },
1341
1342 // Maps
1343
1344 Self::PartMap {part , map} => if let Some(condition) = map.get(part .get(task_state.url) ) {condition.check(task_state)?} else {false},
1345 Self::StringMap{value, map} => if let Some(condition) = map.get(value.get(task_state )?) {condition.check(task_state)?} else {false},
1346
1347 Self::PartNamedPartitioning {named_partitioning, part , map} => if let Some(condition) = map.get(task_state.params.named_partitionings.get(get_str!(named_partitioning, task_state, ConditionError)).ok_or(ConditionError::NamedPartitioningNotFound)?.get_partition_of(part.get(task_state.url).as_deref())) {condition.check(task_state)?} else {false},
1348 Self::StringNamedPartitioning {named_partitioning, value, map} => if let Some(condition) = map.get(task_state.params.named_partitionings.get(get_str!(named_partitioning, task_state, ConditionError)).ok_or(ConditionError::NamedPartitioningNotFound)?.get_partition_of(get_option_str!(value, task_state)) ) {condition.check(task_state)?} else {false},
1349
1350 // Params
1351
1352 Self::FlagIsSet (FlagRef {name: StringSource::String(name), r#type: FlagType::Params}) => task_state.params.flags.contains(name),
1353 Self::FlagIsNotSet(FlagRef {name: StringSource::String(name), r#type: FlagType::Params}) => !task_state.params.flags.contains(name),
1354
1355 Self::FlagIsSet(flag) => flag.get(task_state)?,
1356 Self::FlagIsNotSet(flag) => !flag.get(task_state)?,
1357
1358 Self::VarIs {var, value} => var.get(task_state)?.as_deref() == value.get(task_state)?.as_deref(),
1359
1360 // String source
1361
1362 Self::StringIs {left, right} => get_option_cow!(left, task_state) == get_option_cow!(right, task_state),
1363 Self::StringIsSome(value) => value.get(task_state)?.is_some(),
1364 Self::StringContains {value, substring, at} => at.check(get_str!(value, task_state, ConditionError), get_str!(substring, task_state, ConditionError))?,
1365 Self::StringMatches {value, matcher} => matcher.check(get_option_str!(value, task_state), task_state)?,
1366
1367 // Whole
1368
1369 Self::UrlIs(value) => task_state.url == get_str!(value, task_state, ConditionError),
1370
1371 // Scheme
1372
1373 Self::SchemeIs(value) => task_state.url.scheme() == get_str!(value, task_state, ConditionError),
1374 Self::SchemeIsOneOf(values) => values.contains(Some(task_state.url.scheme())),
1375 Self::SchemeIsInSet(set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(Some(task_state.url.scheme())),
1376
1377 // Host is
1378
1379 Self::HostIs (x) => task_state.url.host_str () == get_option_str!(x, task_state),
1380 Self::NormalizedHostIs (x) => task_state.url.normalized_host () == get_option_str!(x, task_state),
1381 Self::SubdomainIs (x) => task_state.url.subdomain () == get_option_str!(x, task_state),
1382 Self::RegDomainIs (x) => task_state.url.reg_domain () == get_option_str!(x, task_state),
1383 Self::DomainIs (x) => task_state.url.domain () == get_option_str!(x, task_state),
1384 Self::DomainMiddleIs (x) => task_state.url.domain_middle () == get_option_str!(x, task_state),
1385 Self::NotDomainSuffixIs(x) => task_state.url.not_domain_suffix() == get_option_str!(x, task_state),
1386 Self::DomainSuffixIs (x) => task_state.url.domain_suffix () == get_option_str!(x, task_state),
1387
1388 Self::DomainSegmentIs {index, value} => task_state.url.domain_segment (*index) == get_option_str!(value, task_state),
1389 Self::SubdomainSegmentIs {index, value} => task_state.url.subdomain_segment (*index) == get_option_str!(value, task_state),
1390 Self::DomainSuffixSegmentIs {index, value} => task_state.url.domain_suffix_segment(*index) == get_option_str!(value, task_state),
1391
1392 // Host is one of
1393
1394 Self::HostIsOneOf (x) => x.contains(task_state.url.host_str ()),
1395 Self::NormalizedHostIsOneOf (x) => x.contains(task_state.url.normalized_host ()),
1396 Self::SubdomainIsOneOf (x) => x.contains(task_state.url.subdomain ()),
1397 Self::RegDomainIsOneOf (x) => x.contains(task_state.url.reg_domain ()),
1398 Self::DomainIsOneOf (x) => x.contains(task_state.url.domain ()),
1399 Self::DomainMiddleIsOneOf (x) => x.contains(task_state.url.domain_middle ()),
1400 Self::NotDomainSuffixIsOneOf(x) => x.contains(task_state.url.not_domain_suffix()),
1401 Self::DomainSuffixIsOneOf (x) => x.contains(task_state.url.domain_suffix ()),
1402
1403 Self::DomainSegmentIsOneOf {index, values} => values.contains(task_state.url.domain_segment (*index)),
1404 Self::SubdomainSegmentIsOneOf {index, values} => values.contains(task_state.url.subdomain_segment (*index)),
1405 Self::DomainSuffixSegmentIsOneOf {index, values} => values.contains(task_state.url.domain_suffix_segment(*index)),
1406
1407 // Host is in set
1408
1409 Self::HostIsInSet (set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.host_str ()),
1410 Self::NormalizedHostIsInSet (set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.normalized_host ()),
1411 Self::SubdomainIsInSet (set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.subdomain ()),
1412 Self::RegDomainIsInSet (set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.reg_domain ()),
1413 Self::DomainIsInSet (set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.domain ()),
1414 Self::DomainMiddleIsInSet (set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.domain_middle ()),
1415 Self::NotDomainSuffixIsInSet(set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.not_domain_suffix()),
1416 Self::DomainSuffixIsInSet (set) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.domain_suffix ()),
1417
1418 Self::DomainSegmentIsInSet {index, set} => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.domain_segment (*index)),
1419 Self::SubdomainSegmentIsInSet {index, set} => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.subdomain_segment (*index)),
1420 Self::DomainSuffixSegmentIsInSet {index, set} => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.domain_suffix_segment(*index)),
1421
1422 // Misc. host
1423
1424 Self::UrlHasHost => task_state.url.host().is_some(),
1425 Self::HostIsFqdn => matches!(task_state.url.host_details(), Some(HostDetails::Domain(DomainDetails {fqdn_period: Some(_), ..}))),
1426 Self::HostIsDomain => matches!(task_state.url.host_details(), Some(HostDetails::Domain(_))),
1427 Self::HostIsIp => matches!(task_state.url.host_details(), Some(HostDetails::Ipv4(_) | HostDetails::Ipv6(_))),
1428 Self::HostIsIpv4 => matches!(task_state.url.host_details(), Some(HostDetails::Ipv4(_))),
1429 Self::HostIsIpv6 => matches!(task_state.url.host_details(), Some(HostDetails::Ipv6(_))),
1430
1431 // Path
1432
1433 Self::PathIs(value) => task_state.url.path() == get_str!(value, task_state, ConditionError),
1434
1435 Self::PathIsOneOf (values) => values.contains(Some(task_state.url.path())),
1436 Self::PathIsInSet (set ) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(Some(task_state.url.path())),
1437 Self::PathStartsWith(value ) => task_state.url.path().starts_with(get_str!(value, task_state, ConditionError)),
1438 Self::FirstNPathSegmentsIs {n, value} => task_state.url.first_n_path_segments(*n).ok_or(ConditionError::NotEnoughPathSegments)? == get_option_str!(value, task_state),
1439 Self::FirstNPathSegmentsIsOneOf {n, set } => set.contains(task_state.url.first_n_path_segments(*n).ok_or(ConditionError::NotEnoughPathSegments)?),
1440 Self::FirstNPathSegmentsIsInSet {n, set } => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.first_n_path_segments(*n).ok_or(ConditionError::NotEnoughPathSegments)?),
1441 Self::LastNPathSegmentsIs {n, value} => task_state.url.last_n_path_segments(*n).ok_or(ConditionError::NotEnoughPathSegments)? == get_option_str!(value, task_state),
1442 Self::LastNPathSegmentsIsOneOf {n, set } => set.contains(task_state.url.last_n_path_segments(*n).ok_or(ConditionError::NotEnoughPathSegments)?),
1443 Self::LastNPathSegmentsIsInSet {n, set } => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.last_n_path_segments(*n).ok_or(ConditionError::NotEnoughPathSegments)?),
1444
1445 Self::PathHasSegments => task_state.url.path_has_segments(),
1446 Self::HasPathSegment(index) => task_state.url.path_segment(*index).is_some_and(|segment| segment.is_none()),
1447 Self::PathSegmentIs {index, value } => task_state.url.path_segment(*index).ok_or(ConditionError::PathSegmentNotFound)? == get_option_str!(value, task_state),
1448
1449 Self::PathSegmentIsOneOf {index, values} => values.contains(task_state.url.path_segment(*index).ok_or(ConditionError::PathSegmentNotFound)?),
1450 Self::PathSegmentIsInSet {index, set} => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.path_segment(*index).ok_or(ConditionError::PathSegmentNotFound)?),
1451
1452 // Query
1453
1454 Self::QueryIs(value) => task_state.url.query() == get_option_str!(value, task_state),
1455
1456 Self::HasQueryParam(QueryParamSelector {name, index}) => task_state.url.has_query_param(name, *index),
1457
1458 Self::QueryParamIs {param: QueryParamSelector {name, index}, value } => task_state.url.query_param(name, *index).flatten().flatten() == get_option_cow!(value, task_state),
1459
1460 Self::QueryParamIsOneOf {param: QueryParamSelector {name, index}, values} => values.contains(task_state.url.query_param(name, *index).flatten().flatten().as_deref()),
1461 Self::QueryParamIsInSet {param: QueryParamSelector {name, index}, set } => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.query_param(name, *index).flatten().flatten().as_deref()),
1462
1463 // Fragment
1464
1465 Self::FragmentIs (value ) => task_state.url.fragment() == get_option_str!(value, task_state),
1466 Self::FragmentIsOneOf (values) => values.contains(task_state.url.fragment()),
1467 Self::FragmentIsInSet (set ) => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(task_state.url.fragment()),
1468 Self::FragmentIsSomeAndStartsWith(value ) => match task_state.url.fragment() {
1469 Some(fragment) => fragment.starts_with(get_str!(value, task_state, ConditionError)),
1470 None => false
1471 },
1472
1473 // General parts
1474
1475 Self::PartIs {part, value} => part.get(task_state.url) == get_option_cow!(value, task_state),
1476
1477 Self::PartContains {part, value, at} => at.check(&part.get(task_state.url).ok_or(ConditionError::UrlPartIsNone)?, get_str!(value, task_state, ConditionError))?,
1478
1479 Self::PartMatches {part, matcher} => matcher.check (part.get(task_state.url).as_deref(), task_state)?,
1480 Self::PartIsOneOf {part, values } => values .contains(part.get(task_state.url).as_deref()),
1481 Self::PartIsInSet {part, set } => task_state.params.sets.get(get_str!(set, task_state, ConditionError)).ok_or(ConditionError::SetNotFound)?.contains(part.get(task_state.url).as_deref()),
1482
1483 // Misc
1484
1485 Self::Common(common_call) => {
1486 task_state.commons.conditions.get(get_str!(common_call.name, task_state, ConditionError)).ok_or(ConditionError::CommonConditionNotFound)?.check(&TaskStateView {
1487 common_args: Some(&common_call.args.build(task_state)?),
1488 url : task_state.url,
1489 scratchpad : task_state.scratchpad,
1490 context : task_state.context,
1491 job_context: task_state.job_context,
1492 params : task_state.params,
1493 commons : task_state.commons,
1494 #[cfg(feature = "cache")]
1495 cache : task_state.cache,
1496 unthreader : task_state.unthreader
1497 })?
1498 },
1499 Self::CommonCallArg(name) => task_state.common_args.ok_or(ConditionError::NotInCommonContext)?.conditions.get(get_str!(name, task_state, ConditionError)).ok_or(ConditionError::CommonCallArgConditionNotFound)?.check(task_state)?,
1500 #[cfg(feature = "custom")]
1501 Self::Custom(function) => function(task_state)?
1502 })
1503 }
1504}