cranpose_runtime_std/
lib.rs1use std::fmt;
9use std::sync::atomic::{AtomicBool, Ordering};
10use std::sync::{Arc, RwLock};
11use std::time::{Duration, Instant};
12
13#[cfg(feature = "internal")]
14use cranpose_core::internal::FrameClock;
15use cranpose_core::{Clock, Runtime, RuntimeHandle, RuntimeScheduler};
16
17#[cfg(target_arch = "wasm32")]
19struct SyncWaker<F>(F);
20
21#[cfg(target_arch = "wasm32")]
22unsafe impl<F> Sync for SyncWaker<F> {}
23
24#[cfg(target_arch = "wasm32")]
25impl<F: Fn()> SyncWaker<F> {
26 fn call(&self) {
27 (self.0)();
28 }
29}
30
31pub struct StdScheduler {
33 frame_requested: AtomicBool,
34 #[cfg(not(target_arch = "wasm32"))]
35 frame_waker: RwLock<Option<Arc<dyn Fn() + Send + Sync + 'static>>>,
36 #[cfg(target_arch = "wasm32")]
37 frame_waker: RwLock<Option<Arc<SyncWaker<Box<dyn Fn() + Send + 'static>>>>>,
38}
39
40impl StdScheduler {
41 pub fn new() -> Self {
42 Self {
43 frame_requested: AtomicBool::new(false),
44 frame_waker: RwLock::new(None),
45 }
46 }
47
48 pub fn take_frame_request(&self) -> bool {
50 self.frame_requested.swap(false, Ordering::SeqCst)
51 }
52
53 #[cfg(not(target_arch = "wasm32"))]
55 pub fn set_frame_waker(&self, waker: impl Fn() + Send + Sync + 'static) {
56 *self.frame_waker.write().unwrap() = Some(Arc::new(waker));
57 }
58
59 #[cfg(target_arch = "wasm32")]
60 pub fn set_frame_waker(&self, waker: impl Fn() + Send + 'static) {
61 *self.frame_waker.write().unwrap() = Some(Arc::new(SyncWaker(Box::new(waker))));
62 }
63
64 pub fn clear_frame_waker(&self) {
66 *self.frame_waker.write().unwrap() = None;
67 }
68
69 #[cfg(not(target_arch = "wasm32"))]
70 fn wake(&self) {
71 let waker = self.frame_waker.read().unwrap().clone();
72 if let Some(waker) = waker {
73 waker();
74 }
75 }
76
77 #[cfg(target_arch = "wasm32")]
78 fn wake(&self) {
79 let waker = self.frame_waker.read().unwrap().clone();
80 if let Some(waker) = waker {
81 waker.call();
82 }
83 }
84}
85
86impl Default for StdScheduler {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92impl fmt::Debug for StdScheduler {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 f.debug_struct("StdScheduler")
95 .field(
96 "frame_requested",
97 &self.frame_requested.load(Ordering::SeqCst),
98 )
99 .finish()
100 }
101}
102
103impl RuntimeScheduler for StdScheduler {
104 fn schedule_frame(&self) {
105 self.frame_requested.store(true, Ordering::SeqCst);
106 self.wake();
107 }
108}
109
110#[derive(Debug, Default, Clone)]
112pub struct StdClock;
113
114impl Clock for StdClock {
115 type Instant = Instant;
116
117 fn now(&self) -> Self::Instant {
118 Instant::now()
119 }
120
121 fn elapsed_millis(&self, since: Self::Instant) -> u64 {
122 since.elapsed().as_millis() as u64
123 }
124}
125
126impl StdClock {
127 pub fn elapsed(&self, since: Instant) -> Duration {
129 since.elapsed()
130 }
131}
132
133#[derive(Clone)]
135pub struct StdRuntime {
136 scheduler: Arc<StdScheduler>,
137 clock: Arc<StdClock>,
138 runtime: Runtime,
139}
140
141impl StdRuntime {
142 pub fn new() -> Self {
144 let scheduler = Arc::new(StdScheduler::default());
145 let runtime = Runtime::new(scheduler.clone());
146 Self {
147 scheduler,
148 clock: Arc::new(StdClock),
149 runtime,
150 }
151 }
152
153 pub fn runtime(&self) -> Runtime {
155 self.runtime.clone()
156 }
157
158 pub fn runtime_handle(&self) -> RuntimeHandle {
160 self.runtime.handle()
161 }
162
163 #[cfg(feature = "internal")]
165 pub fn frame_clock(&self) -> FrameClock {
166 self.runtime.frame_clock()
167 }
168
169 pub fn scheduler(&self) -> Arc<StdScheduler> {
171 Arc::clone(&self.scheduler)
172 }
173
174 pub fn clock(&self) -> Arc<StdClock> {
176 Arc::clone(&self.clock)
177 }
178
179 pub fn take_frame_request(&self) -> bool {
181 self.scheduler.take_frame_request()
182 }
183
184 #[cfg(not(target_arch = "wasm32"))]
186 pub fn set_frame_waker(&self, waker: impl Fn() + Send + Sync + 'static) {
187 self.scheduler.set_frame_waker(waker);
188 }
189
190 #[cfg(target_arch = "wasm32")]
191 pub fn set_frame_waker(&self, waker: impl Fn() + Send + 'static) {
192 self.scheduler.set_frame_waker(waker);
193 }
194
195 pub fn clear_frame_waker(&self) {
197 self.scheduler.clear_frame_waker();
198 }
199
200 pub fn drain_frame_callbacks(&self, frame_time_nanos: u64) {
202 self.runtime_handle()
203 .drain_frame_callbacks(frame_time_nanos);
204 }
205}
206
207impl fmt::Debug for StdRuntime {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 f.debug_struct("StdRuntime")
210 .field("scheduler", &self.scheduler)
211 .field("clock", &self.clock)
212 .finish()
213 }
214}
215
216impl Default for StdRuntime {
217 fn default() -> Self {
218 Self::new()
219 }
220}
221
222#[cfg(test)]
223#[path = "tests/std_runtime_tests.rs"]
224mod tests;