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