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}