Skip to main content

ferroui_base/styling/
selector_match.rs

1use super::activators::{AndActivatorBuilder, IStyleActivator};
2use std::fmt;
3use std::rc::Rc;
4
5/// Describes how a [`SelectorMatch`] matches a control and its type.
6#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub enum SelectorMatchResult {
8    /// The selector never matches this type.
9    NeverThisType,
10    /// The selector never matches this instance, but can match this type.
11    NeverThisInstance,
12    /// The selector matches this instance based on the activator.
13    Sometimes,
14    /// The selector always matches this instance, but doesn't always match
15    /// this type.
16    AlwaysThisInstance,
17    /// The selector always matches this type.
18    AlwaysThisType,
19}
20
21/// Holds the result of a selector match.
22///
23/// A selector match describes whether and how a selector matches a control,
24/// and in addition whether the selector can ever match a control of the same
25/// type.
26#[derive(Clone)]
27pub struct SelectorMatch {
28    result: SelectorMatchResult,
29    activator: Option<Rc<dyn IStyleActivator>>,
30}
31
32impl SelectorMatch {
33    /// A selector match with the result of [`SelectorMatchResult::NeverThisType`].
34    pub const NEVER_THIS_TYPE: SelectorMatch = SelectorMatch::new(SelectorMatchResult::NeverThisType);
35
36    /// A selector match with the result of [`SelectorMatchResult::NeverThisInstance`].
37    pub const NEVER_THIS_INSTANCE: SelectorMatch = SelectorMatch::new(SelectorMatchResult::NeverThisInstance);
38
39    /// A selector match with the result of [`SelectorMatchResult::AlwaysThisType`].
40    pub const ALWAYS_THIS_TYPE: SelectorMatch = SelectorMatch::new(SelectorMatchResult::AlwaysThisType);
41
42    /// A selector match with the result of [`SelectorMatchResult::AlwaysThisInstance`].
43    pub const ALWAYS_THIS_INSTANCE: SelectorMatch = SelectorMatch::new(SelectorMatchResult::AlwaysThisInstance);
44
45    /// Creates a match with a [`SelectorMatchResult::Sometimes`] result,
46    /// whose state is tracked by `activator`.
47    pub fn sometimes(activator: Rc<dyn IStyleActivator>) -> Self {
48        Self { result: SelectorMatchResult::Sometimes, activator: Some(activator) }
49    }
50
51    /// Creates a match with the specified result and no activator.
52    pub const fn new(result: SelectorMatchResult) -> Self {
53        Self { result, activator: None }
54    }
55
56    /// Whether the match was positive.
57    ///
58    /// The match is positive if the result is `Sometimes`,
59    /// `AlwaysThisInstance` or `AlwaysThisType`.
60    #[inline]
61    pub fn is_match(&self) -> bool {
62        self.result >= SelectorMatchResult::Sometimes
63    }
64
65    /// The result of the selector match.
66    #[inline]
67    pub fn result(&self) -> SelectorMatchResult {
68        self.result
69    }
70
71    /// An activator which tracks the selector match, in the case of
72    /// selectors that can change over time.
73    #[inline]
74    pub fn activator(&self) -> Option<&Rc<dyn IStyleActivator>> {
75        self.activator.as_ref()
76    }
77
78    pub(crate) fn into_activator(self) -> Option<Rc<dyn IStyleActivator>> {
79        self.activator
80    }
81
82    /// Logical-AND the selector match with another.
83    pub fn and(self, other: SelectorMatch) -> SelectorMatch {
84        let result = self.result.min(other.result);
85
86        if result == SelectorMatchResult::Sometimes {
87            let mut activators = AndActivatorBuilder::new();
88            activators.add(self.activator);
89            activators.add(other.activator);
90            SelectorMatch::sometimes(activators.get())
91        } else {
92            SelectorMatch::new(result)
93        }
94    }
95}
96
97impl fmt::Debug for SelectorMatch {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        fmt::Debug::fmt(&self.result, f)
100    }
101}
102
103impl fmt::Display for SelectorMatch {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        fmt::Debug::fmt(&self.result, f)
106    }
107}