use std::{cell::{Ref, RefCell, RefMut}, rc::Rc};
use genawaiter::{rc::{Co, Gen}, Coroutine};
use crate::{Context, Play};
struct State<Game : Play> {
is_in_progress : bool,
game : Game,
}
impl<Game> From<Game> for State<Game> where
Game : Play,
{
fn from(game : Game) -> Self {
Self {
is_in_progress: false,
game,
}
}
}
#[derive(Debug)]
pub enum PlayError {
InUse,
AlreadyStarted,
}
pub struct Host<Game : Play> {
state : Rc<RefCell<State<Game>>>,
}
impl<Game> Host<Game> where
Game : Play,
{
pub fn new(game : Game) -> Self {
let state = Rc::new(RefCell::new(game.into()));
Self { state }
}
pub fn play(&self) -> Result<
impl Coroutine<
Yield = <Game as Play>::Event,
Resume = <Game as Play>::Input,
Return = <Game as Play>::Outcome>,
PlayError>
{
if let Ok(state) = self.state.try_borrow_mut() {
if state.is_in_progress {
return Err(PlayError::AlreadyStarted);
}
}
else {
return Err(PlayError::InUse);
}
let run = move |co : Co<Game::Event, Game::Input>| {
let ctx = Context { host: self.clone(), co };
Game::play(ctx)
};
Ok(Gen::new(run))
}
pub fn game(&self) -> Game where
Game : Copy,
{
self.with_game(|game| *game)
}
pub fn clone_game(&self) -> Game where
Game : Clone,
{
self.with_game(|game| game.clone())
}
pub fn borrow_game(&'_ self) -> Ref<'_, Game> {
Ref::map((*self.state).borrow(), |state| &state.game)
}
pub fn borrow_game_mut(&'_ self) -> RefMut<'_, Game> {
RefMut::map((*self.state).borrow_mut(), |state| &mut state.game)
}
pub fn with_game<F, R>(&'_ self, transact : F) -> R where
for<'r> F : FnOnce(Ref<'r, Game>) -> R
{
transact(self.borrow_game())
}
pub fn with_game_mut<F, R>(&'_ self, transact : F) -> R where
for<'r> F : FnOnce(RefMut<'r, Game>) -> R
{
let borrowed = RefMut::map((*self.state).borrow_mut(), |state| &mut state.game);
transact(borrowed)
}
pub fn process_event(&self, mut event : &mut <Game as Play>::Event) {
self.with_game_mut(|mut game| game.handle_event(&mut event))
}
}
impl<Game> Clone for Host<Game> where
Game : Play,
{
fn clone(&self) -> Self {
Self { state: self.state.clone() }
}
}