ferroui_base/rendering/composition/drawing/
compositor_resource_helpers.rs1use super::ICompositionRenderResource;
2use crate::rendering::composition::server::ServerObjectId;
3use crate::rendering::composition::{Compositor, ICompositorSerializable};
4use std::cell::RefCell;
5use std::rc::{Rc, Weak};
6
7pub struct CompositorRefCountableResource {
9 value: ServerObjectId,
10 ref_count: i32,
11}
12
13impl CompositorRefCountableResource {
14 pub fn new(value: ServerObjectId) -> Self {
15 Self { value, ref_count: 1 }
16 }
17
18 pub fn value(&self) -> ServerObjectId {
19 self.value
20 }
21
22 pub fn ref_count(&self) -> i32 {
23 self.ref_count
24 }
25
26 pub fn add_ref(&mut self) {
27 if self.ref_count <= 0 {
28 panic!("This resource is disposed");
29 }
30 self.ref_count += 1;
31 }
32
33 pub fn release(&mut self, c: &Compositor) -> bool {
36 if self.ref_count <= 0 {
37 panic!("This resource is disposed");
38 }
39 self.ref_count -= 1;
40 if self.ref_count == 0 {
41 c.dispose_on_next_batch(self.value);
42 return true;
43 }
44 false
45 }
46}
47
48struct Entry {
49 compositor: Weak<Compositor>,
50 resource: CompositorRefCountableResource,
51}
52
53#[derive(Default)]
56pub struct CompositorResourceHolder {
57 dictionary: RefCell<Vec<Entry>>,
58}
59
60fn is_compositor(entry: &Entry, compositor: &Compositor) -> bool {
61 std::ptr::eq(entry.compositor.as_ptr(), compositor)
62}
63
64impl CompositorResourceHolder {
65 pub fn new() -> Self {
66 Self::default()
67 }
68
69 pub fn is_attached(&self) -> bool {
71 !self.dictionary.borrow().is_empty()
72 }
73
74 pub fn create_or_add_ref(
79 &self,
80 compositor: &Rc<Compositor>,
81 owner: Option<Rc<dyn ICompositorSerializable>>,
82 factory: impl FnOnce(&Rc<Compositor>) -> ServerObjectId,
83 ) -> (ServerObjectId, bool) {
84 {
85 let mut dictionary = self.dictionary.borrow_mut();
86 if let Some(entry) = dictionary.iter_mut().find(|e| is_compositor(e, compositor)) {
87 entry.resource.add_ref();
88 return (entry.resource.value(), false);
89 }
90 }
91 let resource = factory(compositor);
92 self.dictionary
93 .borrow_mut()
94 .push(Entry { compositor: Rc::downgrade(compositor), resource: CompositorRefCountableResource::new(resource) });
95 if let Some(owner) = owner {
96 compositor.register_for_serialization(owner);
97 }
98 (resource, true)
99 }
100
101 pub fn try_get_for_compositor(&self, compositor: &Compositor) -> Option<ServerObjectId> {
102 self.dictionary.borrow().iter().find(|e| is_compositor(e, compositor)).map(|e| e.resource.value())
103 }
104
105 pub fn get_for_compositor(&self, compositor: &Compositor) -> ServerObjectId {
106 match self.try_get_for_compositor(compositor) {
107 Some(value) => value,
108 None => panic!("This resource doesn't exist on that compositor"),
109 }
110 }
111
112 pub fn release(&self, compositor: &Compositor) -> bool {
115 let mut dictionary = self.dictionary.borrow_mut();
116 let Some(index) = dictionary.iter().position(|e| is_compositor(e, compositor)) else {
117 panic!("This resource doesn't exist on that compositor");
118 };
119 if dictionary[index].resource.release(compositor) {
120 dictionary.remove(index);
121 return true;
122 }
123 false
124 }
125
126 fn compositors(&self) -> Vec<Rc<Compositor>> {
127 self.dictionary.borrow().iter().filter_map(|e| e.compositor.upgrade()).collect()
128 }
129
130 pub fn process_property_change_notification(
133 &self,
134 old_value: Option<&dyn ICompositionRenderResource>,
135 new_value: Option<&dyn ICompositionRenderResource>,
136 ) {
137 if let Some(old_resource) = old_value {
138 self.transitive_release_all(old_resource);
139 }
140 if let Some(new_resource) = new_value {
141 self.transitive_add_ref_all(new_resource);
142 }
143 }
144
145 pub fn transitive_release_all(&self, old_resource: &dyn ICompositionRenderResource) {
146 for compositor in self.compositors() {
147 old_resource.release_on_compositor(&compositor);
148 }
149 }
150
151 pub fn transitive_add_ref_all(&self, new_resource: &dyn ICompositionRenderResource) {
152 for compositor in self.compositors() {
153 new_resource.add_ref_on_compositor(&compositor);
154 }
155 }
156
157 pub fn register_for_invalidation_on_all_compositors(&self, serializable: &Rc<dyn ICompositorSerializable>) {
158 for compositor in self.compositors() {
159 compositor.register_for_serialization(serializable.clone());
160 }
161 }
162}