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