cranpose_ui/modifier/
semantics.rs1use std::{
2 cell::Cell,
3 fmt,
4 hash::{Hash, Hasher},
5 rc::Rc,
6};
7
8use cranpose_core::NodeId;
9use cranpose_foundation::{
10 DelegatableNode, ModifierNode, ModifierNodeChain, ModifierNodeContext, ModifierNodeElement,
11 NodeCapabilities, NodeState, SemanticsConfiguration, SemanticsNode as SemanticsNodeTrait,
12};
13
14use super::{Modifier, ModifierChainHandle};
15use crate::render_state::AppContextId;
16
17#[derive(Clone, Default)]
49pub struct SemanticsRequester {
50 binding: Rc<Cell<Option<SemanticsBinding>>>,
51}
52
53#[derive(Clone, Copy)]
54struct SemanticsBinding {
55 app_context: AppContextId,
56 node_id: NodeId,
57}
58
59impl SemanticsRequester {
60 pub fn new() -> Self {
63 Self::default()
64 }
65
66 pub fn invalidate(&self) {
72 if let Some(binding) = self.binding.get() {
73 crate::semantics_dispatch::schedule_semantics_invalidation_in(
74 binding.app_context,
75 binding.node_id,
76 );
77 }
78 }
79
80 pub fn node_id(&self) -> Option<NodeId> {
82 self.binding.get().map(|binding| binding.node_id)
83 }
84
85 fn bind(&self, binding: Option<SemanticsBinding>) {
86 self.binding.set(binding);
87 }
88
89 fn binding_here(node_id: Option<NodeId>) -> Option<SemanticsBinding> {
90 Some(SemanticsBinding {
91 app_context: crate::render_state::current_app_context_id_opt()?,
92 node_id: node_id?,
93 })
94 }
95}
96
97impl fmt::Debug for SemanticsRequester {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 f.debug_struct("SemanticsRequester")
100 .field("node_id", &self.node_id())
101 .finish()
102 }
103}
104
105pub(super) struct SemanticsModifierNode {
106 recorder: Rc<dyn Fn(&mut SemanticsConfiguration)>,
107 reads_live_state: bool,
109 state: NodeState,
110}
111
112impl SemanticsModifierNode {
113 pub(super) fn new(
116 recorder: Rc<dyn Fn(&mut SemanticsConfiguration)>,
117 reads_live_state: bool,
118 ) -> Self {
119 Self {
120 recorder,
121 reads_live_state,
122 state: NodeState::new(),
123 }
124 }
125}
126
127impl DelegatableNode for SemanticsModifierNode {
128 fn node_state(&self) -> &NodeState {
129 &self.state
130 }
131}
132
133impl ModifierNode for SemanticsModifierNode {
134 fn as_semantics_node(&self) -> Option<&dyn SemanticsNodeTrait> {
135 Some(self)
136 }
137
138 fn as_semantics_node_mut(&mut self) -> Option<&mut dyn SemanticsNodeTrait> {
139 Some(self)
140 }
141}
142
143pub(crate) struct SemanticsRequesterNode {
144 state: NodeState,
145 requester: SemanticsRequester,
146}
147
148impl SemanticsRequesterNode {
149 pub(crate) fn new(requester: SemanticsRequester) -> Self {
150 Self {
151 state: NodeState::new(),
152 requester,
153 }
154 }
155}
156
157impl DelegatableNode for SemanticsRequesterNode {
158 fn node_state(&self) -> &NodeState {
159 &self.state
160 }
161}
162
163impl ModifierNode for SemanticsRequesterNode {
164 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
165 self.state.set_attached(true);
166 self.requester
167 .bind(SemanticsRequester::binding_here(context.node_id()));
168 }
169
170 fn on_detach(&mut self) {
171 self.state.set_attached(false);
172 self.requester.bind(None);
173 }
174}
175
176#[derive(Clone)]
177pub(crate) struct SemanticsRequesterElement {
178 requester: SemanticsRequester,
179}
180
181impl SemanticsRequesterElement {
182 pub(crate) fn new(requester: SemanticsRequester) -> Self {
183 Self { requester }
184 }
185}
186
187impl fmt::Debug for SemanticsRequesterElement {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 f.write_str("SemanticsRequesterElement")
190 }
191}
192
193impl PartialEq for SemanticsRequesterElement {
194 fn eq(&self, other: &Self) -> bool {
195 Rc::ptr_eq(&self.requester.binding, &other.requester.binding)
196 }
197}
198
199impl Eq for SemanticsRequesterElement {}
200
201impl Hash for SemanticsRequesterElement {
202 fn hash<H: Hasher>(&self, state: &mut H) {
203 Rc::as_ptr(&self.requester.binding).hash(state);
204 }
205}
206
207impl ModifierNodeElement for SemanticsRequesterElement {
208 type Node = SemanticsRequesterNode;
209
210 fn create(&self) -> Self::Node {
211 SemanticsRequesterNode::new(self.requester.clone())
212 }
213
214 fn update(&self, node: &mut Self::Node) {
215 if !Rc::ptr_eq(&node.requester.binding, &self.requester.binding) {
216 let bound = node.requester.binding.get();
217 node.requester.bind(None);
218 node.requester = self.requester.clone();
219 node.requester.bind(bound);
220 }
221 }
222
223 fn inspector_name(&self) -> &'static str {
224 "semanticsRequester"
225 }
226
227 fn capabilities(&self) -> NodeCapabilities {
228 NodeCapabilities::NONE
229 }
230}
231
232impl SemanticsNodeTrait for SemanticsModifierNode {
233 fn merge_semantics(&self, config: &mut SemanticsConfiguration) {
234 (self.recorder)(config);
235 }
236
237 fn reach(&self) -> cranpose_foundation::SemanticsReach {
238 cranpose_foundation::SemanticsReach::merged_by(self, self.reads_live_state)
239 }
240}
241
242#[derive(Clone)]
243pub(super) struct SemanticsElement {
244 recorder: Rc<dyn Fn(&mut SemanticsConfiguration)>,
245 reads_live_state: bool,
246}
247
248impl SemanticsElement {
249 pub(super) fn new(
252 recorder: Rc<dyn Fn(&mut SemanticsConfiguration)>,
253 reads_live_state: bool,
254 ) -> Self {
255 Self {
256 recorder,
257 reads_live_state,
258 }
259 }
260}
261
262impl fmt::Debug for SemanticsElement {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 f.write_str("SemanticsElement")
265 }
266}
267
268impl PartialEq for SemanticsElement {
269 fn eq(&self, _other: &Self) -> bool {
270 true
271 }
272}
273
274impl Eq for SemanticsElement {}
275
276impl Hash for SemanticsElement {
277 fn hash<H: Hasher>(&self, state: &mut H) {
278 "semantics".hash(state);
279 }
280}
281
282impl ModifierNodeElement for SemanticsElement {
283 type Node = SemanticsModifierNode;
284
285 fn create(&self) -> Self::Node {
286 SemanticsModifierNode::new(Rc::clone(&self.recorder), self.reads_live_state)
287 }
288
289 fn update(&self, node: &mut Self::Node) {
290 node.recorder = Rc::clone(&self.recorder);
291 node.reads_live_state = self.reads_live_state;
292 }
293
294 fn capabilities(&self) -> NodeCapabilities {
295 NodeCapabilities::SEMANTICS
296 }
297
298 fn always_update(&self) -> bool {
299 true
300 }
301}
302
303fn merge_semantics_from_node(node: &dyn ModifierNode, config: &mut SemanticsConfiguration) -> bool {
304 let mut merged = false;
305
306 if let Some(semantics) = node.as_semantics_node() {
307 semantics.merge_semantics(config);
308 merged = true;
309 }
310
311 node.for_each_delegate(&mut |delegate| {
312 if merge_semantics_from_node(delegate, config) {
313 merged = true;
314 }
315 });
316
317 merged
318}
319
320pub(crate) fn collect_semantics_from_chain(
321 chain: &ModifierNodeChain,
322) -> Option<SemanticsConfiguration> {
323 if !chain.has_capability(NodeCapabilities::SEMANTICS) {
324 return None;
325 }
326
327 let mut config = SemanticsConfiguration::default();
328 let mut merged = false;
329 chain.for_each_node_with_capability(NodeCapabilities::SEMANTICS, |_ref, node| {
330 if merge_semantics_from_node(node, &mut config) {
331 merged = true;
332 }
333 });
334
335 if merged { Some(config) } else { None }
336}
337
338fn reach_of_node(node: &dyn ModifierNode) -> cranpose_foundation::SemanticsReach {
339 let mut reach = node
340 .as_semantics_node()
341 .map(cranpose_foundation::SemanticsNode::reach)
342 .unwrap_or_default();
343 node.for_each_delegate(&mut |delegate| {
344 reach = reach.union(reach_of_node(delegate));
345 });
346 reach
347}
348
349pub(crate) fn semantics_reach_of_chain(
350 chain: &ModifierNodeChain,
351) -> cranpose_foundation::SemanticsReach {
352 let mut reach = cranpose_foundation::SemanticsReach::default();
353 if !chain.has_capability(NodeCapabilities::SEMANTICS) {
354 return reach;
355 }
356 chain.for_each_node_with_capability(NodeCapabilities::SEMANTICS, |_ref, node| {
357 reach = reach.union(reach_of_node(node));
358 });
359 reach
360}
361
362pub fn collect_semantics_from_modifier(modifier: &Modifier) -> Option<SemanticsConfiguration> {
364 let mut handle = ModifierChainHandle::new();
365 handle.update(modifier);
366 collect_semantics_from_chain(handle.chain())
367}