ferroui_base/styling/
style_query.rs1use super::activators::AndActivatorBuilder;
2use super::{ContainerQuery, SelectorMatch, SelectorMatchResult, StyleBase};
3use crate::StyledElement;
4use std::fmt;
5use std::rc::Rc;
6
7pub(crate) trait StyleQueryNode: 'static {
9 fn is_combinator(&self) -> bool;
14
15 fn to_string(&self, owner: Option<&ContainerQuery>) -> String;
18
19 fn evaluate(
21 &self,
22 control: &StyledElement,
23 parent: Option<&StyleBase>,
24 subscribe: bool,
25 container_name: Option<&str>,
26 ) -> SelectorMatch;
27
28 fn move_previous(&self) -> Option<&StyleQuery>;
30
31 #[allow(dead_code)]
33 fn move_previous_or_parent(&self) -> Option<&StyleQuery>;
34}
35
36#[derive(Clone)]
41pub struct StyleQuery(pub(crate) Rc<dyn StyleQueryNode>);
42
43
44impl PartialEq for StyleQuery {
47 #[inline]
48 fn eq(&self, other: &Self) -> bool {
49 std::ptr::addr_eq(Rc::as_ptr(&self.0), Rc::as_ptr(&other.0))
50 }
51}
52
53impl StyleQuery {
54 pub(crate) fn new(node: impl StyleQueryNode) -> Self {
55 StyleQuery(Rc::new(node))
56 }
57
58 #[inline]
59 pub(crate) fn is_combinator(&self) -> bool {
60 self.0.is_combinator()
61 }
62
63 pub fn match_(
71 &self,
72 control: &StyledElement,
73 parent: Option<&StyleBase>,
74 subscribe: bool,
75 container_name: Option<&str>,
76 ) -> SelectorMatch {
77 let mut combinator = None;
81 let mut activators = AndActivatorBuilder::new();
82 let result =
83 Self::match_query(control, self, parent, subscribe, &mut activators, &mut combinator, container_name);
84 let mut match_ = if result == SelectorMatchResult::Sometimes {
85 SelectorMatch::sometimes(activators.get())
86 } else {
87 SelectorMatch::new(result)
88 };
89
90 if match_.is_match() {
93 if let Some(combinator) = combinator {
94 match_ = match_.and(combinator.match_(control, parent, subscribe, container_name));
95
96 match_ = match match_.result() {
100 SelectorMatchResult::AlwaysThisType => SelectorMatch::ALWAYS_THIS_INSTANCE,
101 SelectorMatchResult::NeverThisType => SelectorMatch::NEVER_THIS_INSTANCE,
102 _ => match_,
103 };
104 }
105 }
106
107 match_
108 }
109
110 pub(crate) fn evaluate(
112 &self,
113 control: &StyledElement,
114 parent: Option<&StyleBase>,
115 subscribe: bool,
116 container_name: Option<&str>,
117 ) -> SelectorMatch {
118 self.0.evaluate(control, parent, subscribe, container_name)
119 }
120
121 pub fn to_string_with_owner(&self, owner: Option<&ContainerQuery>) -> String {
123 self.0.to_string(owner)
124 }
125
126 fn match_query<'a>(
127 control: &StyledElement,
128 query: &'a StyleQuery,
129 parent: Option<&StyleBase>,
130 subscribe: bool,
131 activators: &mut AndActivatorBuilder,
132 combinator: &mut Option<&'a StyleQuery>,
133 container_name: Option<&str>,
134 ) -> SelectorMatchResult {
135 let previous = query.0.move_previous();
136
137 if let Some(previous) = previous {
141 if !previous.is_combinator() {
142 let previous_match =
143 Self::match_query(control, previous, parent, subscribe, activators, combinator, container_name);
144
145 if previous_match < SelectorMatchResult::Sometimes {
146 return previous_match;
147 }
148 }
149 }
150
151 let match_ = query.0.evaluate(control, parent, subscribe, container_name);
153
154 if !match_.is_match() {
155 *combinator = None;
156 return match_.result();
157 }
158
159 let result = match_.result();
160 activators.add(match_.into_activator());
161
162 if let Some(previous) = previous {
163 if previous.is_combinator() {
164 *combinator = Some(previous);
165 }
166 }
167
168 result
169 }
170}
171
172impl fmt::Display for StyleQuery {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 f.write_str(&self.0.to_string(None))
175 }
176}
177
178impl fmt::Debug for StyleQuery {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 f.write_str(&self.0.to_string(None))
181 }
182}