pax_runtime_api/properties/
mod.rs1use serde::{Deserialize, Serialize};
2use std::{marker::PhantomData, rc::Rc};
3
4mod graph_operations;
5mod properties_table;
6#[cfg(test)]
7mod tests;
8mod untyped_property;
9
10use crate::{EasingCurve, Interpolatable, TransitionQueueEntry};
11
12use self::properties_table::{PropertyType, PROPERTY_TIME};
13use properties_table::PROPERTY_TABLE;
14pub use untyped_property::UntypedProperty;
15
16mod private {
18 slotmap::new_key_type!(
19 pub struct PropertyId;
20 );
21}
22
23pub trait PropertyValue: Default + Clone + Interpolatable + 'static {}
27impl<T: Default + Clone + Interpolatable + 'static> PropertyValue for T {}
28
29impl<T: PropertyValue> Interpolatable for Property<T> {
30 fn interpolate(&self, other: &Self, t: f64) -> Self {
31 let cp_self = self.clone();
32 let cp_other = other.clone();
33 Property::computed(
34 move || cp_self.get().interpolate(&cp_other.get(), t),
35 &[self.untyped(), other.untyped()],
36 )
37 }
38}
39#[derive(Clone)]
42pub struct Property<T> {
43 untyped: UntypedProperty,
44 _phantom: PhantomData<T>,
45}
46
47impl<T: PropertyValue + std::fmt::Debug> std::fmt::Debug for Property<T> {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 write!(f, "Property ({:?})", self.get())
50 }
51}
52
53impl<T: PropertyValue> Property<T> {
54 pub fn new(val: T) -> Self {
55 Self::new_optional_name(val, None)
56 }
57
58 pub fn new_from_untyped(untyped: UntypedProperty) -> Self {
59 Self {
60 untyped,
61 _phantom: PhantomData {},
62 }
63 }
64
65 pub fn computed(evaluator: impl Fn() -> T + 'static, dependents: &[UntypedProperty]) -> Self {
66 Self::computed_with_config(evaluator, dependents, None)
67 }
68
69 pub fn new_with_name(val: T, name: &str) -> Self {
70 Self::new_optional_name(val, Some(name))
71 }
72
73 pub fn computed_with_name(
74 evaluator: impl Fn() -> T + 'static,
75 dependents: &[UntypedProperty],
76 name: &str,
77 ) -> Self {
78 Self::computed_with_config(evaluator, dependents, Some(name))
79 }
80
81 fn new_optional_name(val: T, name: Option<&str>) -> Self {
82 Self {
83 untyped: UntypedProperty::new(val, Vec::with_capacity(0), PropertyType::Literal, name),
84 _phantom: PhantomData {},
85 }
86 }
87
88 fn computed_with_config(
89 evaluator: impl Fn() -> T + 'static,
90 dependents: &[UntypedProperty],
91 name: Option<&str>,
92 ) -> Self {
93 let inbound: Vec<_> = dependents.iter().map(|v| v.get_id()).collect();
94 let start_val = T::default();
95 let evaluator = Rc::new(evaluator);
96 Self {
97 untyped: UntypedProperty::new(
98 start_val,
99 inbound,
100 PropertyType::Computed { evaluator },
101 name,
102 ),
103 _phantom: PhantomData {},
104 }
105 }
106
107 pub fn ease_to(&self, end_val: T, time: u64, curve: EasingCurve) {
108 self.ease_to_value(end_val, time, curve, true);
109 }
110
111 pub fn ease_to_later(&self, end_val: T, time: u64, curve: EasingCurve) {
112 self.ease_to_value(end_val, time, curve, false);
113 }
114
115 fn ease_to_value(&self, end_val: T, time: u64, curve: EasingCurve, overwrite: bool) {
116 PROPERTY_TABLE.with(|t| {
117 t.transition(
118 self.untyped.id,
119 TransitionQueueEntry {
120 duration_frames: time,
121 curve,
122 ending_value: end_val,
123 },
124 overwrite,
125 )
126 })
127 }
128
129 pub fn get(&self) -> T {
133 PROPERTY_TABLE.with(|t| t.get_value(self.untyped.id))
134 }
135
136 pub fn set(&self, val: T) {
139 PROPERTY_TABLE.with(|t| t.set_value(self.untyped.id, val));
140 }
141
142 pub fn update(&self, f: impl FnOnce(&mut T)) {
146 let mut val = self.get();
149 f(&mut val);
150 self.set(val);
151 }
152
153 pub fn read<V>(&self, f: impl FnOnce(&T) -> V) -> V {
157 PROPERTY_TABLE.with(|t| t.read_value(self.untyped.id, f))
158 }
159
160 pub fn replace_with(&self, target: Property<T>) {
167 PROPERTY_TABLE.with(|t| {
168 t.replace_property_keep_outbound_connections::<T>(self.untyped.id, target.untyped.id)
170 })
171 }
172
173 pub fn untyped(&self) -> UntypedProperty {
175 self.untyped.clone()
176 }
177}
178
179impl<T: PropertyValue> Default for Property<T> {
180 fn default() -> Self {
181 Property::new(T::default())
182 }
183}
184
185impl<'de, T: PropertyValue + Deserialize<'de>> Deserialize<'de> for Property<T> {
188 fn deserialize<D>(deserializer: D) -> Result<Property<T>, D::Error>
189 where
190 D: serde::Deserializer<'de>,
191 {
192 let value = T::deserialize(deserializer)?;
193 Ok(Property::new(value))
194 }
195}
196
197impl<T: PropertyValue + Serialize> Serialize for Property<T> {
198 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
199 where
200 S: serde::Serializer,
201 {
202 self.get().serialize(serializer)
204 }
205}
206
207pub fn property_table_total_properties_count() -> usize {
209 PROPERTY_TABLE.with(|t| t.total_properties_count())
210}
211
212pub fn register_time(prop: &Property<u64>) {
213 PROPERTY_TIME.with_borrow_mut(|time| *time = prop.clone());
214}