cranpose_runtime_std/
lib.rs1#![deny(unsafe_code)]
9
10#[cfg(target_arch = "wasm32")]
11use std::cell::RefCell;
12use std::fmt;
13use std::sync::atomic::{AtomicBool, Ordering};
14use std::sync::Arc;
15#[cfg(not(target_arch = "wasm32"))]
16use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
17use std::time::Duration;
18use web_time::Instant;
19
20#[cfg(feature = "internal")]
21use cranpose_core::internal::FrameClock;
22use cranpose_core::{Clock, Runtime, RuntimeHandle, RuntimeScheduler};
23
24#[cfg(not(target_arch = "wasm32"))]
25type NativeFrameWaker = Arc<dyn Fn() + Send + Sync + 'static>;
26
27pub struct StdScheduler {
29 frame_requested: AtomicBool,
30 #[cfg(not(target_arch = "wasm32"))]
31 frame_waker: RwLock<Option<NativeFrameWaker>>,
32 #[cfg(target_arch = "wasm32")]
33 frame_waker: RefCell<Option<Box<dyn Fn() + 'static>>>,
34}
35
36impl StdScheduler {
37 pub fn new() -> Self {
38 Self {
39 frame_requested: AtomicBool::new(false),
40 frame_waker: Default::default(),
41 }
42 }
43
44 pub fn take_frame_request(&self) -> bool {
46 self.frame_requested.swap(false, Ordering::SeqCst)
47 }
48
49 pub fn has_frame_request(&self) -> bool {
51 self.frame_requested.load(Ordering::SeqCst)
52 }
53
54 #[cfg(not(target_arch = "wasm32"))]
56 pub fn set_frame_waker(&self, waker: impl Fn() + Send + Sync + 'static) {
57 let old_waker = {
58 let mut frame_waker = self.frame_waker_write();
59 frame_waker.replace(Arc::new(waker))
60 };
61 drop(old_waker);
62 }
63
64 #[cfg(target_arch = "wasm32")]
65 pub fn set_frame_waker(&self, waker: impl Fn() + 'static) {
66 *self.frame_waker.borrow_mut() = Some(Box::new(waker));
67 }
68
69 #[cfg(not(target_arch = "wasm32"))]
71 pub fn clear_frame_waker(&self) {
72 let old_waker = {
73 let mut frame_waker = self.frame_waker_write();
74 frame_waker.take()
75 };
76 drop(old_waker);
77 }
78
79 #[cfg(target_arch = "wasm32")]
81 pub fn clear_frame_waker(&self) {
82 *self.frame_waker.borrow_mut() = None;
83 }
84
85 #[cfg(not(target_arch = "wasm32"))]
86 fn wake(&self) {
87 let waker = self.frame_waker_read().clone();
88 if let Some(waker) = waker {
89 waker();
90 }
91 }
92
93 #[cfg(target_arch = "wasm32")]
94 fn wake(&self) {
95 if let Some(waker) = self.frame_waker.borrow().as_ref() {
96 waker();
97 }
98 }
99
100 #[cfg(not(target_arch = "wasm32"))]
101 fn frame_waker_read(&self) -> RwLockReadGuard<'_, Option<NativeFrameWaker>> {
102 match self.frame_waker.read() {
103 Ok(guard) => guard,
104 Err(poisoned) => poisoned.into_inner(),
105 }
106 }
107
108 #[cfg(not(target_arch = "wasm32"))]
109 fn frame_waker_write(&self) -> RwLockWriteGuard<'_, Option<NativeFrameWaker>> {
110 match self.frame_waker.write() {
111 Ok(guard) => guard,
112 Err(poisoned) => poisoned.into_inner(),
113 }
114 }
115}
116
117impl Default for StdScheduler {
118 fn default() -> Self {
119 Self::new()
120 }
121}
122
123impl fmt::Debug for StdScheduler {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 f.debug_struct("StdScheduler")
126 .field(
127 "frame_requested",
128 &self.frame_requested.load(Ordering::SeqCst),
129 )
130 .finish()
131 }
132}
133
134impl RuntimeScheduler for StdScheduler {
135 fn schedule_frame(&self) {
136 self.frame_requested.store(true, Ordering::SeqCst);
137 self.wake();
138 }
139}
140
141#[derive(Debug, Default, Clone)]
143pub struct StdClock;
144
145impl Clock for StdClock {
146 type Instant = Instant;
147
148 fn now(&self) -> Self::Instant {
149 Instant::now()
150 }
151
152 fn elapsed_millis(&self, since: Self::Instant) -> u64 {
153 since.elapsed().as_millis() as u64
154 }
155}
156
157impl StdClock {
158 pub fn elapsed(&self, since: Instant) -> Duration {
160 since.elapsed()
161 }
162}
163
164#[derive(Clone)]
166pub struct StdRuntime {
167 scheduler: Arc<StdScheduler>,
168 clock: Arc<StdClock>,
169 runtime: Runtime,
170}
171
172impl StdRuntime {
173 pub fn new() -> Self {
175 let scheduler = Arc::new(StdScheduler::default());
176 let runtime = Runtime::new(scheduler.clone());
177 Self {
178 scheduler,
179 clock: Arc::new(StdClock),
180 runtime,
181 }
182 }
183
184 pub fn runtime(&self) -> Runtime {
186 self.runtime.clone()
187 }
188
189 pub fn runtime_handle(&self) -> RuntimeHandle {
191 self.runtime.handle()
192 }
193
194 #[cfg(feature = "internal")]
196 pub fn frame_clock(&self) -> FrameClock {
197 self.runtime.frame_clock()
198 }
199
200 pub fn scheduler(&self) -> Arc<StdScheduler> {
202 Arc::clone(&self.scheduler)
203 }
204
205 pub fn clock(&self) -> Arc<StdClock> {
207 Arc::clone(&self.clock)
208 }
209
210 pub fn take_frame_request(&self) -> bool {
212 self.scheduler.take_frame_request()
213 }
214
215 pub fn has_frame_request(&self) -> bool {
216 self.scheduler.has_frame_request()
217 }
218
219 #[cfg(not(target_arch = "wasm32"))]
221 pub fn set_frame_waker(&self, waker: impl Fn() + Send + Sync + 'static) {
222 self.scheduler.set_frame_waker(waker);
223 }
224
225 #[cfg(target_arch = "wasm32")]
226 pub fn set_frame_waker(&self, waker: impl Fn() + 'static) {
227 self.scheduler.set_frame_waker(waker);
228 }
229
230 pub fn clear_frame_waker(&self) {
232 self.scheduler.clear_frame_waker();
233 }
234
235 pub fn drain_frame_callbacks(&self, frame_time_nanos: u64) {
237 self.runtime_handle()
238 .drain_frame_callbacks(frame_time_nanos);
239 }
240}
241
242impl fmt::Debug for StdRuntime {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 f.debug_struct("StdRuntime")
245 .field("scheduler", &self.scheduler)
246 .field("clock", &self.clock)
247 .finish()
248 }
249}
250
251impl Default for StdRuntime {
252 fn default() -> Self {
253 Self::new()
254 }
255}
256
257#[cfg(test)]
258#[path = "tests/std_runtime_tests.rs"]
259mod tests;