ferroui_base/rendering/composition/server/
composition_property.rs1use super::IServerObject;
2use crate::rendering::composition::expressions::ExpressionVariant;
3use std::any::{Any, TypeId};
4use std::sync::atomic::{AtomicI32, Ordering};
5
6static NEXT_ID: AtomicI32 = AtomicI32::new(1);
7
8pub struct CompositionProperty {
15 id: i32,
16 name: &'static str,
17 owner: TypeId,
18 owner_name: &'static str,
19 get_variant: Option<fn(&dyn IServerObject) -> ExpressionVariant>,
20 set_variant: Option<fn(&dyn IServerObject, ExpressionVariant)>,
21}
22
23impl CompositionProperty {
24 fn new(
25 id: i32,
26 name: &'static str,
27 owner: TypeId,
28 owner_name: &'static str,
29 get_variant: Option<fn(&dyn IServerObject) -> ExpressionVariant>,
30 set_variant: Option<fn(&dyn IServerObject, ExpressionVariant)>,
31 ) -> Self {
32 Self { id, name, owner, owner_name, get_variant, set_variant }
33 }
34
35 pub fn id(&self) -> i32 {
36 self.id
37 }
38
39 pub fn name(&self) -> &'static str {
40 self.name
41 }
42
43 pub fn owner(&self) -> TypeId {
46 self.owner
47 }
48
49 pub fn owner_name(&self) -> &'static str {
51 self.owner_name
52 }
53
54 pub fn get_variant(&self) -> Option<fn(&dyn IServerObject) -> ExpressionVariant> {
57 self.get_variant
58 }
59
60 pub fn set_variant(&self) -> Option<fn(&dyn IServerObject, ExpressionVariant)> {
66 self.set_variant
67 }
68
69 pub fn register<TOwner: Any, TField>(
72 name: &'static str,
73 owner_name: &'static str,
74 get_field: fn(&dyn IServerObject) -> TField,
75 set_field: fn(&dyn IServerObject, TField),
76 get_variant: Option<fn(&dyn IServerObject) -> ExpressionVariant>,
77 set_variant: Option<fn(&dyn IServerObject, ExpressionVariant)>,
78 ) -> CompositionPropertyOf<TField> {
79 let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
80 CompositionPropertyOf {
81 base: CompositionProperty::new(id, name, TypeId::of::<TOwner>(), owner_name, get_variant, set_variant),
82 get_field,
83 set_field,
84 }
85 }
86}
87
88impl PartialEq for CompositionProperty {
89 fn eq(&self, other: &Self) -> bool {
90 self.id == other.id
91 }
92}
93
94impl Eq for CompositionProperty {}
95
96impl std::hash::Hash for CompositionProperty {
97 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
98 self.id.hash(state);
99 }
100}
101
102impl std::fmt::Debug for CompositionProperty {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 write!(f, "{}.{}#{}", self.owner_name, self.name, self.id)
105 }
106}
107
108pub struct CompositionPropertyOf<T> {
111 base: CompositionProperty,
112 get_field: fn(&dyn IServerObject) -> T,
113 set_field: fn(&dyn IServerObject, T),
114}
115
116impl<T> CompositionPropertyOf<T> {
117 pub fn base(&self) -> &CompositionProperty {
119 &self.base
120 }
121
122 pub fn get_field(&self, obj: &dyn IServerObject) -> T {
124 (self.get_field)(obj)
125 }
126
127 pub fn set_field(&self, obj: &dyn IServerObject, value: T) {
129 (self.set_field)(obj, value)
130 }
131}
132
133impl<T> std::ops::Deref for CompositionPropertyOf<T> {
134 type Target = CompositionProperty;
135
136 fn deref(&self) -> &CompositionProperty {
137 &self.base
138 }
139}
140
141pub fn props_of<P: Any>(obj: &dyn IServerObject) -> &P {
146 match obj.get_props(TypeId::of::<P>()).and_then(|props| props.downcast_ref::<P>()) {
147 Some(props) => props,
148 None => panic!("the server object does not have the properties of {}", std::any::type_name::<P>()),
149 }
150}