Skip to content

Instantly share code, notes, and snippets.

@not-fl3

not-fl3/past2.rs Secret

Last active September 23, 2021 22:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save not-fl3/ba67e22ba7554f1850e25aaf3f3c07e8 to your computer and use it in GitHub Desktop.
Save not-fl3/ba67e22ba7554f1850e25aaf3f3c07e8 to your computer and use it in GitHub Desktop.
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Poll, RawWaker, RawWakerVTable, Waker};
struct Player {
pos: i32,
}
struct Move {
player: Rc<RefCell<Player>>,
dir: i32,
amount: i32,
}
impl Future for Move {
type Output = ();
fn poll(
mut self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> {
self.player.borrow_mut().pos += self.dir;
self.amount -= 1;
if self.amount == 0 {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
struct Wait {
frames: i32,
}
impl Future for Wait {
type Output = ();
fn poll(
mut self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> {
self.frames -= 1;
if self.frames == 0 {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
fn persist<T>(frames: &mut Vec<([u8; 32], i32)>, x: &T, player: &Player) {
assert_eq!(std::mem::size_of::<T>(), 32);
let mut bytes: [u8; 32] = [0; 32];
unsafe {
std::ptr::copy_nonoverlapping(x as *const T as *mut u8, bytes.as_mut_ptr(), 32);
}
frames.push((bytes, player.pos));
}
fn restore<T>(frames: &Vec<([u8; 32], i32)>, frame: usize, x: &mut T, player: &mut Player) {
assert_eq!(std::mem::size_of::<T>(), 32);
player.pos = frames[frame].1;
unsafe {
std::ptr::copy_nonoverlapping(frames[frame].0.as_ptr(), x as *mut T as *mut u8, 32);
}
}
fn resume<T: Future<Output = ()>>(fut: &mut T) -> bool {
fn waker() -> Waker {
unsafe fn clone(data: *const ()) -> RawWaker {
RawWaker::new(data, &VTABLE)
}
unsafe fn wake(_data: *const ()) {
panic!(
"macroquad does not support waking futures, please use coroutines, \
otherwise your pending cutscene will block until the next frame"
)
}
unsafe fn wake_by_ref(data: *const ()) {
wake(data)
}
unsafe fn drop(_data: *const ()) {
// Nothing to do
}
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
let raw_waker = RawWaker::new(std::ptr::null(), &VTABLE);
unsafe { Waker::from_raw(raw_waker) }
}
let mut pinned_cutscene = unsafe { Pin::new_unchecked(fut) };
let waker = waker();
let mut futures_context = std::task::Context::from_waker(&waker);
if let Poll::Ready(()) = pinned_cutscene.as_mut().poll(&mut futures_context) {
return false;
}
true
}
fn main() {
let player = Rc::new(RefCell::new(Player { pos: 5 }));
let mut frame = 0;
// cutscene - a long sequence of actions, moving player around
let mut cutscene = async {
Move {
player: player.clone(),
dir: 1,
amount: 8,
}
.await;
Wait { frames: 5 }.await;
Move {
player: player.clone(),
dir: 1,
amount: 8,
}
.await;
};
let mut frames = vec![];
loop {
println!("frame: {}, player at: {}", frame, player.borrow().pos);
persist(&mut frames, &cutscene, &*player.borrow());
if !resume(&mut cutscene) {
break;
}
frame += 1;
}
println!("restoring frame 5");
restore(&frames, 5, &mut cutscene, &mut player.borrow_mut());
frame = 5;
loop {
println!("frame: {}, player at: {}", frame, player.borrow().pos);
if !resume(&mut cutscene) {
break;
}
frame += 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment