Skip to main content

pax_runtime_api/properties/
mod.rs

1use serde::{Deserialize, Serialize};
2use std::{marker::PhantomData, rc::Rc};
3
4mod graph_operations;
5mod local_property;
6mod properties_table;
7mod shared_graph;
8mod shared_property;
9#[cfg(test)]
10mod shared_tests;
11#[cfg(test)]
12mod tests;
13mod untyped_property;
14
15use crate::{Duration, EasingCurve, Interpolatable, TransitionQueueEntry};
16
17use self::properties_table::{PropertyType, PROPERTY_MILLIS, PROPERTY_TIME};
18pub use local_property::LocalProperty;
19pub use properties_table::EffectDrainReport;
20use properties_table::PROPERTY_TABLE;
21#[doc(hidden)]
22pub use shared_graph::{BindingScope, BindingScopeGuard};
23pub use shared_graph::{PropertyGraph, PropertyGraphGuard};
24pub use shared_property::{Property, Published, SharedPropertyValue};
25pub use untyped_property::UntypedProperty;
26
27/// Sealed PropertyId needed for slotmap (strictly internal)
28mod private {
29    slotmap::new_key_type!(
30        pub struct PropertyId;
31    );
32}
33
34/// Value operations shared by local and transferable properties.
35///
36/// Values must be cloneable for `.get()`, interpolatable for transitions, and
37/// `'static` because properties are stored in the runtime graph.
38pub trait PropertyValue: Default + Clone + Interpolatable + 'static {}
39impl<T: Default + Clone + Interpolatable + 'static> PropertyValue for T {}
40
41/// Owner-thread binding operations used by generated component factories.
42///
43/// Shared fields publish values while their evaluators stay in the entered
44/// [`PropertyGraph`]. Local fields retain ordinary lazy graph semantics.
45pub trait PropertyBinding<T: PropertyValue>: Sized {
46    /// Creates independent literal state of this field's ownership kind.
47    fn from_value(value: T) -> Self;
48    /// Obtains the owner-thread view used by generated bindings.
49    fn local(&self) -> LocalProperty<T>;
50    /// Aliases a local binding, preserving a shared source when one exists.
51    fn from_local(source: LocalProperty<T>) -> Self;
52    /// Reads a field for conversion, using local snapshots during an explicit
53    /// graph conversion and ordinary value semantics otherwise.
54    #[doc(hidden)]
55    fn value_for_conversion(&self) -> T;
56}
57
58thread_local! {
59    static GRAPH_CONVERSION: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
60}
61
62pub(crate) fn with_graph_conversion<R>(f: impl FnOnce() -> R) -> R {
63    struct Restore(bool);
64    impl Drop for Restore {
65        fn drop(&mut self) {
66            GRAPH_CONVERSION.with(|active| active.set(self.0));
67        }
68    }
69    let _restore = Restore(GRAPH_CONVERSION.with(|active| active.replace(true)));
70    f()
71}
72
73// Utility method to inspect total entry count in property table.
74pub fn property_table_total_properties_count() -> usize {
75    PROPERTY_TABLE.with(|t| t.total_properties_count())
76}
77
78#[doc(hidden)]
79pub fn register_effect_property(prop: &LocalProperty<()>) {
80    PROPERTY_TABLE.with(|t| t.register_effect(prop.untyped.id));
81}
82
83#[doc(hidden)]
84pub fn register_effect_property_with_name(prop: &LocalProperty<()>, debug_name: &str) {
85    PROPERTY_TABLE.with(|t| t.register_effect_with_name(prop.untyped.id, Some(debug_name)));
86}
87
88#[doc(hidden)]
89pub fn drain_effects(max_iterations: usize) -> usize {
90    PROPERTY_TABLE.with(|t| t.drain_effects(max_iterations))
91}
92
93#[doc(hidden)]
94pub fn drain_effects_with_report(max_iterations: usize) -> EffectDrainReport {
95    PROPERTY_TABLE.with(|t| t.drain_effects_with_report(max_iterations))
96}
97
98#[doc(hidden)]
99pub fn property_outbound_debug_names(prop: &UntypedProperty) -> Vec<String> {
100    PROPERTY_TABLE.with(|t| t.outbound_debug_names(prop.id))
101}
102
103#[doc(hidden)]
104pub fn property_has_direct_outbound(source: &UntypedProperty, outbound: &UntypedProperty) -> bool {
105    PROPERTY_TABLE.with(|t| t.has_direct_outbound(source.id, outbound.id))
106}
107
108// Registers the runtime clock property used by transition/easing machinery.
109pub fn register_time(prop: &LocalProperty<u64>) {
110    PROPERTY_TIME.with_borrow_mut(|time| *time = prop.clone());
111}
112
113// Registers the runtime wall clock property used by time-based transition/easing machinery.
114pub fn register_millis(prop: &LocalProperty<u64>) {
115    PROPERTY_MILLIS.with_borrow_mut(|time| *time = prop.clone());
116}
117
118/// Current runtime frame used to distinguish initial binding from later changes.
119#[doc(hidden)]
120pub fn current_frame() -> u64 {
121    PROPERTY_TIME.with_borrow(|time| time.get())
122}