ferroui_base/rendering/composition/server/
server_property_host.rs1use super::{CompositionProperty, IServerObject, IServerRenderResource, ServerCompositor};
5use crate::rendering::composition::animations::IAnimationInstance;
6use crate::rendering::composition::expressions::ExpressionVariant;
7use crate::rendering::composition::transport::{BatchResource, BatchStreamReader};
8use std::rc::Rc;
9use std::time::Duration;
10
11pub struct ServerValueChange<'a> {
15 pub equal: bool,
17 pub old_resource: Option<Rc<dyn IServerRenderResource>>,
19 pub new_resource: Option<Rc<dyn IServerRenderResource>>,
21 pub assign: &'a mut dyn FnMut(),
23}
24
25pub trait IServerPropertyHost {
28 fn server_compositor(&self) -> Option<Rc<ServerCompositor>>;
31
32 fn set_value(&self, property: &'static CompositionProperty, change: ServerValueChange<'_>) {
37 let _ = property;
38 (change.assign)();
39 }
40}
41
42pub trait IServerAnimatedPropertyHost: IServerPropertyHost {
46 fn set_animated_value(
51 &self,
52 property: &'static CompositionProperty,
53 current_value: ExpressionVariant,
54 committed_at: Duration,
55 animation: Rc<dyn IAnimationInstance>,
56 );
57
58 fn remove_animation_for_property(&self, property: &'static CompositionProperty);
62
63 fn notify_animated_value_changed(&self, property: &'static CompositionProperty);
65}
66
67pub struct ServerResourceRef<T: ?Sized> {
71 pub value: Rc<T>,
72 pub resource: Option<Rc<dyn IServerRenderResource>>,
73}
74
75impl<T: ?Sized> Clone for ServerResourceRef<T> {
76 fn clone(&self) -> Self {
77 Self { value: self.value.clone(), resource: self.resource.clone() }
78 }
79}
80
81impl<T: ?Sized> ServerResourceRef<T> {
82 pub fn from_value(value: Rc<T>) -> Self {
84 Self { value, resource: None }
85 }
86
87 pub fn ptr_eq(&self, other: &Self) -> bool {
88 std::ptr::addr_eq(Rc::as_ptr(&self.value), Rc::as_ptr(&other.value))
89 }
90}
91
92pub fn resolve_resource<T: ?Sized + 'static>(
95 resource: Option<BatchResource<T>>,
96 compositor: Option<&Rc<ServerCompositor>>,
97 cast: fn(Rc<dyn IServerObject>) -> Option<Rc<T>>,
98) -> Option<ServerResourceRef<T>> {
99 match resource? {
100 BatchResource::Value(value) => Some(ServerResourceRef::from_value(value)),
101 BatchResource::Server(id) => {
102 let Some(object) = compositor.and_then(|c| c.get_object(id)) else {
103 panic!("a batch refers to server object {id:?}, which does not exist");
104 };
105 let resource = object.clone().as_render_resource();
106 match cast(object) {
107 Some(value) => Some(ServerResourceRef { value, resource }),
108 None => panic!("server object {id:?} is not of the type the property expects"),
109 }
110 }
111 }
112}
113
114pub fn read_resource<T: ?Sized + crate::rendering::composition::transport::BatchResourceValue>(
116 reader: &mut BatchStreamReader<'_>,
117 compositor: Option<&Rc<ServerCompositor>>,
118 cast: fn(Rc<dyn IServerObject>) -> Option<Rc<T>>,
119) -> Option<ServerResourceRef<T>> {
120 resolve_resource(reader.read_resource::<T>(), compositor, cast)
121}
122
123pub fn read_server_object(
125 reader: &mut BatchStreamReader<'_>,
126 compositor: Option<&Rc<ServerCompositor>>,
127) -> Option<Rc<dyn IServerObject>> {
128 let id = reader.read_server_object()?;
129 match compositor.and_then(|c| c.get_object(id)) {
130 Some(object) => Some(object),
131 None => panic!("a batch refers to server object {id:?}, which does not exist"),
132 }
133}
134
135pub trait ServerPropertyValue {
141 fn differs(&self, other: &Self) -> bool;
142
143 fn default_equals(&self, other: &Self) -> bool {
144 !self.differs(other)
145 }
146}
147
148macro_rules! impl_server_property_value {
149 ($($ty:ty),* $(,)?) => {$(
150 impl ServerPropertyValue for $ty {
151 #[inline]
152 fn differs(&self, other: &Self) -> bool {
153 self != other
154 }
155 }
156 )*};
157}
158
159impl_server_property_value!(
160 bool,
161 crate::Vector,
162 crate::Vector3D,
163 crate::Size,
164 crate::Matrix,
165 crate::CornerRadius,
166 crate::RelativePoint,
167 crate::RelativeScalar,
168 crate::RelativeRect,
169 crate::numerics::Quaternion,
170 crate::media::Color,
171 crate::media::RenderOptions,
172 crate::media::TextOptions,
173 crate::media::ImmutableExperimentalAcrylicMaterial,
174 crate::media::PenLineCap,
175 crate::media::PenLineJoin,
176 crate::media::AlignmentX,
177 crate::media::AlignmentY,
178 crate::media::Stretch,
179 crate::media::TileMode,
180 crate::rendering::RendererDebugOverlays,
181 crate::rendering::LayoutPassTiming,
182 crate::rendering::composition::CompositionTransparencyLevel,
183);
184
185impl ServerPropertyValue for f32 {
186 fn differs(&self, other: &Self) -> bool {
187 self != other
188 }
189 fn default_equals(&self, other: &Self) -> bool {
190 self == other || (self.is_nan() && other.is_nan())
191 }
192}
193
194impl ServerPropertyValue for f64 {
195 fn differs(&self, other: &Self) -> bool {
196 self != other
197 }
198 fn default_equals(&self, other: &Self) -> bool {
199 self == other || (self.is_nan() && other.is_nan())
200 }
201}
202
203impl<T: ?Sized> ServerPropertyValue for Option<Rc<T>> {
205 fn differs(&self, other: &Self) -> bool {
206 match (self, other) {
207 (Some(a), Some(b)) => !std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b)),
208 (None, None) => false,
209 _ => true,
210 }
211 }
212}
213
214impl<T: ?Sized> ServerPropertyValue for Option<std::sync::Arc<T>> {
216 fn differs(&self, other: &Self) -> bool {
217 match (self, other) {
218 (Some(a), Some(b)) => !std::ptr::addr_eq(std::sync::Arc::as_ptr(a), std::sync::Arc::as_ptr(b)),
219 (None, None) => false,
220 _ => true,
221 }
222 }
223}
224
225impl<T: ?Sized> ServerPropertyValue for Option<ServerResourceRef<T>> {
226 fn differs(&self, other: &Self) -> bool {
227 match (self, other) {
228 (Some(a), Some(b)) => !a.ptr_eq(b),
229 (None, None) => false,
230 _ => true,
231 }
232 }
233}
234
235impl<T: ?Sized> ServerPropertyValue for Option<BatchResource<T>> {
236 fn differs(&self, other: &Self) -> bool {
237 match (self, other) {
238 (Some(BatchResource::Value(a)), Some(BatchResource::Value(b))) => {
239 !std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b))
240 }
241 (Some(BatchResource::Server(a)), Some(BatchResource::Server(b))) => a != b,
242 (None, None) => false,
243 _ => true,
244 }
245 }
246}
247
248pub trait AsServerRenderResource {
250 fn as_server_render_resource(&self) -> Option<Rc<dyn IServerRenderResource>>;
251}
252
253impl AsServerRenderResource for Option<Rc<dyn IServerObject>> {
254 fn as_server_render_resource(&self) -> Option<Rc<dyn IServerRenderResource>> {
255 self.clone().and_then(|object| object.as_render_resource())
256 }
257}
258
259impl<T: ?Sized> AsServerRenderResource for Option<ServerResourceRef<T>> {
260 fn as_server_render_resource(&self) -> Option<Rc<dyn IServerRenderResource>> {
261 self.as_ref().and_then(|value| value.resource.clone())
262 }
263}