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