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 pub fn has_frame_request(&self) -> bool {
55 self.frame_requested.load(Ordering::SeqCst)
56 }
57
58 #[cfg(not(target_arch = "wasm32"))]
60 pub fn set_frame_waker(&self, waker: impl Fn() + Send + Sync + 'static) {
61 *self.frame_waker.write().unwrap() = Some(Arc::new(waker));
62 }
63
64 #[cfg(target_arch = "wasm32")]
65 pub fn set_frame_waker(&self, waker: impl Fn() + Send + 'static) {
66 *self.frame_waker.write().unwrap() = Some(Arc::new(SyncWaker(Box::new(waker))));
67 }
68
69 pub fn clear_frame_waker(&self) {
71 *self.frame_waker.write().unwrap() = None;
72 }
73
74 #[cfg(not(target_arch = "wasm32"))]
75 fn wake(&self) {
76 let waker = self.frame_waker.read().unwrap().clone();
77 if let Some(waker) = waker {
78 waker();
79 }
80 }
81
82 #[cfg(target_arch = "wasm32")]
83 fn wake(&self) {
84 let waker = self.frame_waker.read().unwrap().clone();
85 if let Some(waker) = waker {
86 waker.call();
87 }
88 }
89}
90
91impl Default for StdScheduler {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl fmt::Debug for StdScheduler {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 f.debug_struct("StdScheduler")
100 .field(
101 "frame_requested",
102 &self.frame_requested.load(Ordering::SeqCst),
103 )
104 .finish()
105 }
106}
107
108impl RuntimeScheduler for StdScheduler {
109 fn schedule_frame(&self) {
110 self.frame_requested.store(true, Ordering::SeqCst);
111 self.wake();
112 }
113}
114
115#[derive(Debug, Default, Clone)]
117pub struct StdClock;
118
119impl Clock for StdClock {
120 type Instant = Instant;
121
122 fn now(&self) -> Self::Instant {
123 Instant::now()
124 }
125
126 fn elapsed_millis(&self, since: Self::Instant) -> u64 {
127 since.elapsed().as_millis() as u64
128 }
129}
130
131impl StdClock {
132 pub fn elapsed(&self, since: Instant) -> Duration {
134 since.elapsed()
135 }
136}
137
138#[derive(Clone)]
140pub struct StdRuntime {
141 scheduler: Arc<StdScheduler>,
142 clock: Arc<StdClock>,
143 runtime: Runtime,
144}
145
146impl StdRuntime {
147 pub fn new() -> Self {
149 let scheduler = Arc::new(StdScheduler::default());
150 let runtime = Runtime::new(scheduler.clone());
151 Self {
152 scheduler,
153 clock: Arc::new(StdClock),
154 runtime,
155 }
156 }
157
158 pub fn runtime(&self) -> Runtime {
160 self.runtime.clone()
161 }
162
163 pub fn runtime_handle(&self) -> RuntimeHandle {
165 self.runtime.handle()
166 }
167
168 #[cfg(feature = "internal")]
170 pub fn frame_clock(&self) -> FrameClock {
171 self.runtime.frame_clock()
172 }
173
174 pub fn scheduler(&self) -> Arc<StdScheduler> {
176 Arc::clone(&self.scheduler)
177 }
178
179 pub fn clock(&self) -> Arc<StdClock> {
181 Arc::clone(&self.clock)
182 }
183
184 pub fn take_frame_request(&self) -> bool {
186 self.scheduler.take_frame_request()
187 }
188
189 pub fn has_frame_request(&self) -> bool {
190 self.scheduler.has_frame_request()
191 }
192
193 #[cfg(not(target_arch = "wasm32"))]
195 pub fn set_frame_waker(&self, waker: impl Fn() + Send + Sync + 'static) {
196 self.scheduler.set_frame_waker(waker);
197 }
198
199 #[cfg(target_arch = "wasm32")]
200 pub fn set_frame_waker(&self, waker: impl Fn() + Send + 'static) {
201 self.scheduler.set_frame_waker(waker);
202 }
203
204 pub fn clear_frame_waker(&self) {
206 self.scheduler.clear_frame_waker();
207 }
208
209 pub fn drain_frame_callbacks(&self, frame_time_nanos: u64) {
211 self.runtime_handle()
212 .drain_frame_callbacks(frame_time_nanos);
213 }
214}
215
216impl fmt::Debug for StdRuntime {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 f.debug_struct("StdRuntime")
219 .field("scheduler", &self.scheduler)
220 .field("clock", &self.clock)
221 .finish()
222 }
223}
224
225impl Default for StdRuntime {
226 fn default() -> Self {
227 Self::new()
228 }
229}
230
231#[cfg(test)]
232#[path = "tests/std_runtime_tests.rs"]
233mod tests;