use super::{CompositionProperty, IServerObject, IServerRenderResource, ServerCompositor};
use crate::rendering::composition::animations::IAnimationInstance;
use crate::rendering::composition::expressions::ExpressionVariant;
use crate::rendering::composition::transport::{BatchResource, BatchStreamReader};
use std::rc::Rc;
use std::time::Duration;
pub struct ServerValueChange<'a> {
pub equal: bool,
pub old_resource: Option<Rc<dyn IServerRenderResource>>,
pub new_resource: Option<Rc<dyn IServerRenderResource>>,
pub assign: &'a mut dyn FnMut(),
}
pub trait IServerPropertyHost {
fn server_compositor(&self) -> Option<Rc<ServerCompositor>>;
fn set_value(&self, property: &'static CompositionProperty, change: ServerValueChange<'_>) {
let _ = property;
(change.assign)();
}
}
pub trait IServerAnimatedPropertyHost: IServerPropertyHost {
fn set_animated_value(
&self,
property: &'static CompositionProperty,
current_value: ExpressionVariant,
committed_at: Duration,
animation: Rc<dyn IAnimationInstance>,
);
fn remove_animation_for_property(&self, property: &'static CompositionProperty);
fn notify_animated_value_changed(&self, property: &'static CompositionProperty);
}
pub struct ServerResourceRef<T: ?Sized> {
pub value: Rc<T>,
pub resource: Option<Rc<dyn IServerRenderResource>>,
}
impl<T: ?Sized> Clone for ServerResourceRef<T> {
fn clone(&self) -> Self {
Self { value: self.value.clone(), resource: self.resource.clone() }
}
}
impl<T: ?Sized> ServerResourceRef<T> {
pub fn from_value(value: Rc<T>) -> Self {
Self { value, resource: None }
}
pub fn ptr_eq(&self, other: &Self) -> bool {
std::ptr::addr_eq(Rc::as_ptr(&self.value), Rc::as_ptr(&other.value))
}
}
pub fn resolve_resource<T: ?Sized + 'static>(
resource: Option<BatchResource<T>>,
compositor: Option<&Rc<ServerCompositor>>,
cast: fn(Rc<dyn IServerObject>) -> Option<Rc<T>>,
) -> Option<ServerResourceRef<T>> {
match resource? {
BatchResource::Value(value) => Some(ServerResourceRef::from_value(value)),
BatchResource::Server(id) => {
let Some(object) = compositor.and_then(|c| c.get_object(id)) else {
panic!("a batch refers to server object {id:?}, which does not exist");
};
let resource = object.clone().as_render_resource();
match cast(object) {
Some(value) => Some(ServerResourceRef { value, resource }),
None => panic!("server object {id:?} is not of the type the property expects"),
}
}
}
}
pub fn read_resource<T: ?Sized + crate::rendering::composition::transport::BatchResourceValue>(
reader: &mut BatchStreamReader<'_>,
compositor: Option<&Rc<ServerCompositor>>,
cast: fn(Rc<dyn IServerObject>) -> Option<Rc<T>>,
) -> Option<ServerResourceRef<T>> {
resolve_resource(reader.read_resource::<T>(), compositor, cast)
}
pub fn read_server_object(
reader: &mut BatchStreamReader<'_>,
compositor: Option<&Rc<ServerCompositor>>,
) -> Option<Rc<dyn IServerObject>> {
let id = reader.read_server_object()?;
match compositor.and_then(|c| c.get_object(id)) {
Some(object) => Some(object),
None => panic!("a batch refers to server object {id:?}, which does not exist"),
}
}
pub trait ServerPropertyValue {
fn differs(&self, other: &Self) -> bool;
fn default_equals(&self, other: &Self) -> bool {
!self.differs(other)
}
}
macro_rules! impl_server_property_value {
($($ty:ty),* $(,)?) => {$(
impl ServerPropertyValue for $ty {
#[inline]
fn differs(&self, other: &Self) -> bool {
self != other
}
}
)*};
}
impl_server_property_value!(
bool,
crate::Vector,
crate::Vector3D,
crate::Size,
crate::Matrix,
crate::CornerRadius,
crate::RelativePoint,
crate::RelativeScalar,
crate::RelativeRect,
crate::numerics::Quaternion,
crate::media::Color,
crate::media::RenderOptions,
crate::media::TextOptions,
crate::media::ImmutableExperimentalAcrylicMaterial,
crate::media::PenLineCap,
crate::media::PenLineJoin,
crate::media::AlignmentX,
crate::media::AlignmentY,
crate::media::Stretch,
crate::media::TileMode,
crate::rendering::RendererDebugOverlays,
crate::rendering::LayoutPassTiming,
crate::rendering::composition::CompositionTransparencyLevel,
);
impl ServerPropertyValue for f32 {
fn differs(&self, other: &Self) -> bool {
self != other
}
fn default_equals(&self, other: &Self) -> bool {
self == other || (self.is_nan() && other.is_nan())
}
}
impl ServerPropertyValue for f64 {
fn differs(&self, other: &Self) -> bool {
self != other
}
fn default_equals(&self, other: &Self) -> bool {
self == other || (self.is_nan() && other.is_nan())
}
}
impl<T: ?Sized> ServerPropertyValue for Option<Rc<T>> {
fn differs(&self, other: &Self) -> bool {
match (self, other) {
(Some(a), Some(b)) => !std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b)),
(None, None) => false,
_ => true,
}
}
}
impl<T: ?Sized> ServerPropertyValue for Option<std::sync::Arc<T>> {
fn differs(&self, other: &Self) -> bool {
match (self, other) {
(Some(a), Some(b)) => !std::ptr::addr_eq(std::sync::Arc::as_ptr(a), std::sync::Arc::as_ptr(b)),
(None, None) => false,
_ => true,
}
}
}
impl<T: ?Sized> ServerPropertyValue for Option<ServerResourceRef<T>> {
fn differs(&self, other: &Self) -> bool {
match (self, other) {
(Some(a), Some(b)) => !a.ptr_eq(b),
(None, None) => false,
_ => true,
}
}
}
impl<T: ?Sized> ServerPropertyValue for Option<BatchResource<T>> {
fn differs(&self, other: &Self) -> bool {
match (self, other) {
(Some(BatchResource::Value(a)), Some(BatchResource::Value(b))) => {
!std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b))
}
(Some(BatchResource::Server(a)), Some(BatchResource::Server(b))) => a != b,
(None, None) => false,
_ => true,
}
}
}
pub trait AsServerRenderResource {
fn as_server_render_resource(&self) -> Option<Rc<dyn IServerRenderResource>>;
}
impl AsServerRenderResource for Option<Rc<dyn IServerObject>> {
fn as_server_render_resource(&self) -> Option<Rc<dyn IServerRenderResource>> {
self.clone().and_then(|object| object.as_render_resource())
}
}
impl<T: ?Sized> AsServerRenderResource for Option<ServerResourceRef<T>> {
fn as_server_render_resource(&self) -> Option<Rc<dyn IServerRenderResource>> {
self.as_ref().and_then(|value| value.resource.clone())
}
}