cranpose_core/
frame_clock.rs1use crate::runtime::RuntimeHandle;
2use crate::FrameCallbackId;
3use std::cell::RefCell;
4use std::future::Future;
5use std::pin::Pin;
6use std::rc::Rc;
7use std::task::{Context, Poll, Waker};
8
9#[derive(Clone)]
10pub struct FrameClock {
11 runtime: RuntimeHandle,
12}
13
14impl FrameClock {
15 pub fn new(runtime: RuntimeHandle) -> Self {
16 Self { runtime }
17 }
18
19 pub fn runtime_handle(&self) -> RuntimeHandle {
20 self.runtime.clone()
21 }
22
23 pub fn with_frame_nanos(
24 &self,
25 callback: impl FnOnce(u64) + 'static,
26 ) -> FrameCallbackRegistration {
27 let mut callback_opt = Some(callback);
28 let runtime = self.runtime.clone();
29 match runtime.register_frame_callback(move |time| {
30 if let Some(callback) = callback_opt.take() {
31 callback(time);
32 }
33 }) {
34 Some(id) => FrameCallbackRegistration::new(runtime, id),
35 None => FrameCallbackRegistration::inactive(runtime),
36 }
37 }
38
39 pub fn with_frame_millis(
40 &self,
41 callback: impl FnOnce(u64) + 'static,
42 ) -> FrameCallbackRegistration {
43 self.with_frame_nanos(move |nanos| {
44 let millis = nanos / 1_000_000;
45 callback(millis);
46 })
47 }
48
49 pub fn next_frame(&self) -> NextFrame {
50 NextFrame::new(self.clone())
51 }
52}
53
54pub struct FrameCallbackRegistration {
55 runtime: RuntimeHandle,
56 id: Option<FrameCallbackId>,
57}
58
59struct NextFrameState {
60 registration: Option<FrameCallbackRegistration>,
61 time: Option<u64>,
62 waker: Option<Waker>,
63}
64
65impl NextFrameState {
66 fn new() -> Self {
67 Self {
68 registration: None,
69 time: None,
70 waker: None,
71 }
72 }
73}
74
75pub struct NextFrame {
76 clock: FrameClock,
77 state: Rc<RefCell<NextFrameState>>,
78}
79
80impl NextFrame {
81 fn new(clock: FrameClock) -> Self {
82 Self {
83 clock,
84 state: Rc::new(RefCell::new(NextFrameState::new())),
85 }
86 }
87}
88
89impl Future for NextFrame {
90 type Output = u64;
91
92 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
93 if let Some(time) = self.state.borrow().time {
94 return Poll::Ready(time);
95 }
96
97 {
98 let mut state = self.state.borrow_mut();
99 state.waker = Some(cx.waker().clone());
100 if state.registration.is_none() {
101 drop(state);
102 let state = Rc::downgrade(&self.state);
103 let registration = self.clock.with_frame_nanos(move |time| {
104 if let Some(state) = state.upgrade() {
105 let mut state = state.borrow_mut();
106 state.time = Some(time);
107 state.registration.take();
108 if let Some(waker) = state.waker.take() {
109 waker.wake();
110 }
111 }
112 });
113 self.state.borrow_mut().registration = Some(registration);
114 }
115 }
116
117 if let Some(time) = self.state.borrow().time {
118 Poll::Ready(time)
119 } else {
120 Poll::Pending
121 }
122 }
123}
124
125impl Drop for NextFrame {
126 fn drop(&mut self) {
127 if let Some(registration) = self.state.borrow_mut().registration.take() {
128 drop(registration);
129 }
130 }
131}
132
133impl FrameCallbackRegistration {
134 fn new(runtime: RuntimeHandle, id: FrameCallbackId) -> Self {
135 Self {
136 runtime,
137 id: Some(id),
138 }
139 }
140
141 fn inactive(runtime: RuntimeHandle) -> Self {
142 Self { runtime, id: None }
143 }
144
145 pub fn cancel(mut self) {
146 if let Some(id) = self.id.take() {
147 self.runtime.cancel_frame_callback(id);
148 }
149 }
150}
151
152impl Drop for FrameCallbackRegistration {
153 fn drop(&mut self) {
154 if let Some(id) = self.id.take() {
155 self.runtime.cancel_frame_callback(id);
156 }
157 }
158}