ferroui_base/rendering/composition/server/
server_render_resource.rs1use super::{IAnimatedServerObject, ServerCompositor, ServerObject, ServerValueChange};
2use std::cell::{Cell, RefCell};
3use std::rc::{Rc, Weak};
4
5pub trait IServerRenderResourceObserver {
8 fn dependency_queued_invalidate(&self, sender: &dyn IServerRenderResource);
9}
10
11pub trait IServerRenderResource: IServerRenderResourceObserver {
14 fn add_observer(&self, observer: &Rc<dyn IServerRenderResourceObserver>);
15 fn remove_observer(&self, observer: &Rc<dyn IServerRenderResourceObserver>);
16 fn queued_invalidate(&self);
17}
18
19pub trait IServerRenderResourceHost: IServerRenderResource {
21 fn compositor(&self) -> Option<Rc<ServerCompositor>>;
23
24 fn as_render_resource_rc(&self) -> Option<Rc<dyn IServerRenderResource>>;
26
27 fn resource_property_changed(&self) {}
30}
31
32struct ObserverEntry {
33 observer: Weak<dyn IServerRenderResourceObserver>,
34 count: u32,
35}
36
37#[derive(Default)]
43pub struct ServerRenderResourceCore {
44 pending_invalidation: Cell<bool>,
45 disposed: Cell<bool>,
46 observers: RefCell<Vec<ObserverEntry>>,
47}
48
49fn same_observer(a: &Weak<dyn IServerRenderResourceObserver>, b: &Rc<dyn IServerRenderResourceObserver>) -> bool {
50 std::ptr::addr_eq(a.as_ptr(), Rc::as_ptr(b))
51}
52
53impl ServerRenderResourceCore {
54 pub fn new() -> Self {
55 Self::default()
56 }
57
58 pub fn is_disposed(&self) -> bool {
59 self.disposed.get()
60 }
61
62 pub fn set_value(&self, host: &dyn IServerRenderResourceHost, change: ServerValueChange<'_>) {
66 if change.equal {
67 return;
68 }
69
70 if self.disposed.get() {
71 (change.assign)();
72 return;
73 }
74
75 let observer: Option<Rc<dyn IServerRenderResourceObserver>> =
76 host.as_render_resource_rc().map(|this| this as Rc<dyn IServerRenderResourceObserver>);
77
78 if let (Some(old_child), Some(observer)) = (&change.old_resource, &observer) {
79 old_child.remove_observer(observer);
80 }
81
82 (change.assign)();
83
84 if let (Some(new_child), Some(observer)) = (&change.new_resource, &observer) {
85 new_child.add_observer(observer);
86 }
87
88 self.invalidated(host);
89 }
90
91 pub fn set_list_value(
97 &self,
98 host: &dyn IServerRenderResourceHost,
99 old_children: Vec<Rc<dyn IServerRenderResource>>,
100 new_children: Vec<Rc<dyn IServerRenderResource>>,
101 assign: &mut dyn FnMut(),
102 ) {
103 if self.disposed.get() {
104 assign();
105 return;
106 }
107
108 let observer: Option<Rc<dyn IServerRenderResourceObserver>> =
109 host.as_render_resource_rc().map(|this| this as Rc<dyn IServerRenderResourceObserver>);
110
111 if let Some(observer) = &observer {
112 for child in &old_children {
113 child.remove_observer(observer);
114 }
115 }
116
117 assign();
118
119 if let Some(observer) = &observer {
120 for child in &new_children {
121 child.add_observer(observer);
122 }
123 }
124
125 self.invalidated(host);
126 }
127
128 pub fn remove_observers_from_property(
130 &self,
131 host: &dyn IServerRenderResourceHost,
132 resource: Option<&Rc<dyn IServerRenderResource>>,
133 ) {
134 if let (Some(resource), Some(this)) = (resource, host.as_render_resource_rc()) {
135 let observer: Rc<dyn IServerRenderResourceObserver> = this;
136 resource.remove_observer(&observer);
137 }
138 }
139
140 pub fn invalidated(&self, host: &dyn IServerRenderResourceHost) {
144 if !self.pending_invalidation.get() {
146 self.pending_invalidation.set(true);
147 if let (Some(compositor), Some(this)) = (host.compositor(), host.as_render_resource_rc()) {
148 compositor.enqueue_render_resource_for_invalidation(this);
149 }
150 host.resource_property_changed();
151 }
152 }
153
154 pub fn dispose(&self) {
155 self.disposed.set(true);
156 self.observers.borrow_mut().clear();
157 }
158
159 pub fn dependency_queued_invalidate(&self, host: &dyn IServerRenderResourceHost) {
160 if let (Some(compositor), Some(this)) = (host.compositor(), host.as_render_resource_rc()) {
161 compositor.enqueue_render_resource_for_invalidation(this);
162 }
163 }
164
165 pub fn add_observer(&self, observer: &Rc<dyn IServerRenderResourceObserver>) {
166 debug_assert!(!self.disposed.get());
167 if self.disposed.get() {
168 return;
169 }
170 let mut observers = self.observers.borrow_mut();
171 match observers.iter_mut().find(|e| same_observer(&e.observer, observer)) {
172 Some(entry) => entry.count += 1,
173 None => observers.push(ObserverEntry { observer: Rc::downgrade(observer), count: 1 }),
174 }
175 }
176
177 pub fn remove_observer(&self, observer: &Rc<dyn IServerRenderResourceObserver>) {
178 if self.disposed.get() {
179 return;
180 }
181 let mut observers = self.observers.borrow_mut();
182 if let Some(index) = observers.iter().position(|e| same_observer(&e.observer, observer)) {
183 observers[index].count -= 1;
184 if observers[index].count == 0 {
185 observers.swap_remove(index);
186 }
187 }
188 }
189
190 pub fn queued_invalidate(&self, this: &dyn IServerRenderResource) {
191 self.pending_invalidation.set(false);
192 let observers: Vec<Rc<dyn IServerRenderResourceObserver>> = {
193 let mut observers = self.observers.borrow_mut();
194 observers.retain(|e| e.observer.strong_count() > 0);
195 observers.iter().filter_map(|e| e.observer.upgrade()).collect()
196 };
197 for observer in observers {
198 observer.dependency_queued_invalidate(this);
199 }
200 }
201
202 pub fn observer_count(&self) -> usize {
204 self.observers.borrow().iter().filter(|e| e.observer.strong_count() > 0).count()
205 }
206}
207
208pub struct SimpleServerRenderResource {
213 compositor: Weak<ServerCompositor>,
214 this: Weak<dyn IServerRenderResource>,
215 core: ServerRenderResourceCore,
216}
217
218impl SimpleServerRenderResource {
219 pub fn new(compositor: &Rc<ServerCompositor>, this: Weak<dyn IServerRenderResource>) -> Self {
221 Self { compositor: Rc::downgrade(compositor), this, core: ServerRenderResourceCore::new() }
222 }
223
224 pub fn compositor(&self) -> Option<Rc<ServerCompositor>> {
225 self.compositor.upgrade()
226 }
227
228 pub fn core(&self) -> &ServerRenderResourceCore {
229 &self.core
230 }
231
232 pub fn is_disposed(&self) -> bool {
233 self.core.is_disposed()
234 }
235
236 pub fn as_render_resource_rc(&self) -> Option<Rc<dyn IServerRenderResource>> {
237 self.this.upgrade()
238 }
239}
240
241#[macro_export]
248#[doc(hidden)]
249macro_rules! __impl_simple_server_render_resource {
250 ($ty:ty, $base:ident) => {
251 impl $crate::rendering::composition::server::IServerRenderResourceObserver for $ty {
252 fn dependency_queued_invalidate(
253 &self,
254 _sender: &dyn $crate::rendering::composition::server::IServerRenderResource,
255 ) {
256 self.$base.core().dependency_queued_invalidate(self);
257 }
258 }
259
260 impl $crate::rendering::composition::server::IServerRenderResource for $ty {
261 fn add_observer(
262 &self,
263 observer: &::std::rc::Rc<dyn $crate::rendering::composition::server::IServerRenderResourceObserver>,
264 ) {
265 self.$base.core().add_observer(observer);
266 }
267
268 fn remove_observer(
269 &self,
270 observer: &::std::rc::Rc<dyn $crate::rendering::composition::server::IServerRenderResourceObserver>,
271 ) {
272 self.$base.core().remove_observer(observer);
273 }
274
275 fn queued_invalidate(&self) {
276 self.$base.core().queued_invalidate(self);
277 }
278 }
279
280 impl $crate::rendering::composition::server::IServerRenderResourceHost for $ty {
281 fn compositor(&self) -> Option<::std::rc::Rc<$crate::rendering::composition::server::ServerCompositor>> {
282 self.$base.compositor()
283 }
284
285 fn as_render_resource_rc(
286 &self,
287 ) -> Option<::std::rc::Rc<dyn $crate::rendering::composition::server::IServerRenderResource>> {
288 self.$base.as_render_resource_rc()
289 }
290 }
291
292 impl $crate::rendering::composition::server::IServerPropertyHost for $ty {
293 fn server_compositor(
294 &self,
295 ) -> Option<::std::rc::Rc<$crate::rendering::composition::server::ServerCompositor>> {
296 self.$base.compositor()
297 }
298
299 fn set_value(
300 &self,
301 _property: &'static $crate::rendering::composition::server::CompositionProperty,
302 change: $crate::rendering::composition::server::ServerValueChange<'_>,
303 ) {
304 self.$base.core().set_value(self, change);
305 }
306 }
307 };
308}
309
310pub use crate::__impl_simple_server_render_resource as impl_simple_server_render_resource;
311
312pub struct ServerRenderResource {
317 object: ServerObject,
318 this: Weak<dyn IServerRenderResource>,
319 core: ServerRenderResourceCore,
320}
321
322impl ServerRenderResource {
323 pub fn new(
325 compositor: &Rc<ServerCompositor>,
326 owner: Weak<dyn IAnimatedServerObject>,
327 this: Weak<dyn IServerRenderResource>,
328 ) -> Self {
329 Self { object: ServerObject::new(compositor, owner), this, core: ServerRenderResourceCore::new() }
330 }
331
332 pub fn object(&self) -> &ServerObject {
334 &self.object
335 }
336
337 pub fn compositor(&self) -> Option<Rc<ServerCompositor>> {
338 self.object.compositor()
339 }
340
341 pub fn core(&self) -> &ServerRenderResourceCore {
342 &self.core
343 }
344
345 pub fn is_disposed(&self) -> bool {
346 self.core.is_disposed()
347 }
348
349 pub fn as_render_resource_rc(&self) -> Option<Rc<dyn IServerRenderResource>> {
350 self.this.upgrade()
351 }
352}
353
354#[macro_export]
366#[doc(hidden)]
367macro_rules! __impl_server_render_resource {
368 ($ty:ty, $base:ident, composition_property: $get:expr) => {
369 $crate::rendering::composition::server::impl_server_render_resource!(@resource $ty, $base);
370
371 impl $crate::rendering::composition::server::IServerAnimatedPropertyHost for $ty {
372 fn set_animated_value(
373 &self,
374 property: &'static $crate::rendering::composition::server::CompositionProperty,
375 current_value: $crate::rendering::composition::expressions::ExpressionVariant,
376 committed_at: ::std::time::Duration,
377 animation: ::std::rc::Rc<dyn $crate::rendering::composition::animations::IAnimationInstance>,
378 ) {
379 self.$base.object().set_animated_value(property, current_value, committed_at, animation);
380 }
381
382 fn remove_animation_for_property(
383 &self,
384 property: &'static $crate::rendering::composition::server::CompositionProperty,
385 ) {
386 self.$base.object().remove_animation_for_property(property);
387 }
388
389 fn notify_animated_value_changed(
390 &self,
391 _property: &'static $crate::rendering::composition::server::CompositionProperty,
392 ) {
393 $crate::rendering::composition::server::IServerObject::values_invalidated(self);
394 }
395 }
396
397 impl $crate::rendering::composition::server::IAnimatedServerObject for $ty {
398 fn server_object(&self) -> &$crate::rendering::composition::server::ServerObject {
399 self.$base.object()
400 }
401
402 fn get_composition_property(
403 &self,
404 field_name: &str,
405 ) -> Option<&'static $crate::rendering::composition::server::CompositionProperty> {
406 ($get)(field_name)
407 }
408
409 fn as_server_object_dyn(&self) -> &dyn $crate::rendering::composition::server::IServerObject {
410 self
411 }
412 }
413 };
414 (@resource $ty:ty, $base:ident) => {
415 impl $crate::rendering::composition::server::IServerRenderResourceObserver for $ty {
416 fn dependency_queued_invalidate(
417 &self,
418 _sender: &dyn $crate::rendering::composition::server::IServerRenderResource,
419 ) {
420 self.$base.core().dependency_queued_invalidate(self);
421 }
422 }
423
424 impl $crate::rendering::composition::server::IServerRenderResource for $ty {
425 fn add_observer(
426 &self,
427 observer: &::std::rc::Rc<dyn $crate::rendering::composition::server::IServerRenderResourceObserver>,
428 ) {
429 self.$base.core().add_observer(observer);
430 }
431
432 fn remove_observer(
433 &self,
434 observer: &::std::rc::Rc<dyn $crate::rendering::composition::server::IServerRenderResourceObserver>,
435 ) {
436 self.$base.core().remove_observer(observer);
437 }
438
439 fn queued_invalidate(&self) {
440 self.$base.core().queued_invalidate(self);
441 }
442 }
443
444 impl $crate::rendering::composition::server::IServerRenderResourceHost for $ty {
445 fn compositor(&self) -> Option<::std::rc::Rc<$crate::rendering::composition::server::ServerCompositor>> {
446 self.$base.compositor()
447 }
448
449 fn as_render_resource_rc(
450 &self,
451 ) -> Option<::std::rc::Rc<dyn $crate::rendering::composition::server::IServerRenderResource>> {
452 self.$base.as_render_resource_rc()
453 }
454 }
455
456 impl $crate::rendering::composition::server::IServerPropertyHost for $ty {
457 fn server_compositor(
458 &self,
459 ) -> Option<::std::rc::Rc<$crate::rendering::composition::server::ServerCompositor>> {
460 self.$base.compositor()
461 }
462
463 fn set_value(
464 &self,
465 _property: &'static $crate::rendering::composition::server::CompositionProperty,
466 change: $crate::rendering::composition::server::ServerValueChange<'_>,
467 ) {
468 self.$base.core().set_value(self, change);
469 }
470 }
471 };
472}
473
474pub use crate::__impl_server_render_resource as impl_server_render_resource;