use crate::integer::{Time,Ratio64}; #[derive(Clone,Copy,Debug)] pub struct Paused; #[derive(Clone,Copy,Debug)] pub struct Unpaused; pub trait PauseState:Copy+std::fmt::Debug{ const IS_PAUSED:bool; fn new()->Self; } impl PauseState for Paused{ const IS_PAUSED:bool=true; fn new()->Self{ Self } } impl PauseState for Unpaused{ const IS_PAUSED:bool=false; fn new()->Self{ Self } } #[derive(Clone,Copy,Debug)] pub struct Realtime{ offset:Time, } impl Realtime{ pub const fn new(offset:Time)->Self{ Self{offset} } } #[derive(Clone,Copy,Debug)] pub struct Scaled{ scale:Ratio64, offset:Time, } impl Scaled{ pub const fn new(scale:Ratio64,offset:Time)->Self{ Self{scale,offset} } const fn with_scale(scale:Ratio64)->Self{ Self{scale,offset:Time::ZERO} } const fn scale(&self,time:Time)->Time{ Time::raw(self.scale.mul_int(time.get())) } const fn get_scale(&self)->Ratio64{ self.scale } fn set_scale(&mut self,time:Time,new_scale:Ratio64){ let new_time=self.get_time(time); self.scale=new_scale; self.set_time(time,new_time); } } pub trait TimerState:Copy+std::fmt::Debug{ fn identity()->Self; fn get_time(&self,time:Time)->Time; fn set_time(&mut self,time:Time,new_time:Time); fn get_offset(&self)->Time; fn set_offset(&mut self,offset:Time); } impl TimerState for Realtime{ fn identity()->Self{ Self{offset:Time::ZERO} } fn get_time(&self,time:Time)->Time{ time+self.offset } fn set_time(&mut self,time:Time,new_time:Time){ self.offset=new_time-time; } fn get_offset(&self)->Time{ self.offset } fn set_offset(&mut self,offset:Time){ self.offset=offset; } } impl TimerState for Scaled{ fn identity()->Self{ Self{scale:Ratio64::ONE,offset:Time::ZERO} } fn get_time(&self,time:Time)->Time{ self.scale(time)+self.offset } fn set_time(&mut self,time:Time,new_time:Time){ self.offset=new_time-self.scale(time); } fn get_offset(&self)->Time{ self.offset } fn set_offset(&mut self,offset:Time){ self.offset=offset; } } #[derive(Clone,Copy,Debug)] pub struct TimerFixed{ state:T, _paused:P, } //scaled timer methods are generic across PauseState impl TimerFixed{ pub fn scaled(time:Time,new_time:Time,scale:Ratio64)->Self{ let mut timer=Self{ state:Scaled::with_scale(scale), _paused:P::new(), }; timer.set_time(time,new_time); timer } pub const fn get_scale(&self)->Ratio64{ self.state.get_scale() } pub fn set_scale(&mut self,time:Time,new_scale:Ratio64){ self.state.set_scale(time,new_scale) } } //pause and unpause is generic across TimerState impl TimerFixed{ pub fn into_unpaused(self,time:Time)->TimerFixed{ let new_time=self.time(time); let mut timer=TimerFixed{ state:self.state, _paused:Unpaused, }; timer.set_time(time,new_time); timer } } impl TimerFixed{ pub fn into_paused(self,time:Time)->TimerFixed{ let new_time=self.time(time); let mut timer=TimerFixed{ state:self.state, _paused:Paused, }; timer.set_time(time,new_time); timer } } //the new constructor and time queries are generic across both impl TimerFixed{ pub fn new(time:Time,new_time:Time)->Self{ let mut timer=Self{ state:T::identity(), _paused:P::new(), }; timer.set_time(time,new_time); timer } pub fn from_state(state:T)->Self{ Self{ state, _paused:P::new(), } } pub fn into_state(self)->T{ self.state } pub fn time(&self,time:Time)->Time{ match P::IS_PAUSED{ true=>self.state.get_offset(), false=>self.state.get_time(time), } } pub fn set_time(&mut self,time:Time,new_time:Time){ match P::IS_PAUSED{ true=>self.state.set_offset(new_time), false=>self.state.set_time(time,new_time), } } } #[derive(Debug)] pub enum Error{ AlreadyPaused, AlreadyUnpaused, } impl std::fmt::Display for Error{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ write!(f,"{self:?}") } } impl std::error::Error for Error{} //wrapper type which holds type state internally #[derive(Clone,Debug)] pub enum Timer{ Paused(TimerFixed), Unpaused(TimerFixed), } impl Timer{ pub fn from_state(state:T,paused:bool)->Self{ match paused{ true=>Self::Paused(TimerFixed::from_state(state)), false=>Self::Unpaused(TimerFixed::from_state(state)), } } pub fn into_state(self)->(T,bool){ match self{ Self::Paused(timer)=>(timer.into_state(),true), Self::Unpaused(timer)=>(timer.into_state(),false), } } pub fn paused(time:Time,new_time:Time)->Self{ Self::Paused(TimerFixed::new(time,new_time)) } pub fn unpaused(time:Time,new_time:Time)->Self{ Self::Unpaused(TimerFixed::new(time,new_time)) } pub fn time(&self,time:Time)->Time{ match self{ Self::Paused(timer)=>timer.time(time), Self::Unpaused(timer)=>timer.time(time), } } pub fn set_time(&mut self,time:Time,new_time:Time){ match self{ Self::Paused(timer)=>timer.set_time(time,new_time), Self::Unpaused(timer)=>timer.set_time(time,new_time), } } pub fn pause(&mut self,time:Time)->Result<(),Error>{ *self=match *self{ Self::Paused(_)=>return Err(Error::AlreadyPaused), Self::Unpaused(timer)=>Self::Paused(timer.into_paused(time)), }; Ok(()) } pub fn unpause(&mut self,time:Time)->Result<(),Error>{ *self=match *self{ Self::Paused(timer)=>Self::Unpaused(timer.into_unpaused(time)), Self::Unpaused(_)=>return Err(Error::AlreadyUnpaused), }; Ok(()) } pub fn is_paused(&self)->bool{ match self{ Self::Paused(_)=>true, Self::Unpaused(_)=>false, } } pub fn set_paused(&mut self,time:Time,paused:bool)->Result<(),Error>{ match paused{ true=>self.pause(time), false=>self.unpause(time), } } } //scaled timer methods are generic across PauseState impl Timer{ pub const fn get_scale(&self)->Ratio64{ match self{ Self::Paused(timer)=>timer.get_scale(), Self::Unpaused(timer)=>timer.get_scale(), } } pub fn set_scale(&mut self,time:Time,new_scale:Ratio64){ match self{ Self::Paused(timer)=>timer.set_scale(time,new_scale), Self::Unpaused(timer)=>timer.set_scale(time,new_scale), } } } #[cfg(test)] mod test{ use super::*; macro_rules! sec { ($s: expr) => { Time::from_secs($s) }; } #[test] fn test_timerfixed_scaled(){ //create a paused timer that reads 0s let timer=TimerFixed::::from_state(Scaled{scale:0.5f32.try_into().unwrap(),offset:sec!(0)}); //the paused timer at 1 second should read 0s assert_eq!(timer.time(sec!(1)),sec!(0)); //unpause it after one second let timer=timer.into_unpaused(sec!(1)); //the timer at 6 seconds should read 2.5s assert_eq!(timer.time(sec!(6)),Time::from_millis(2500)); //pause the timer after 11 seconds let timer=timer.into_paused(sec!(11)); //the paused timer at 20 seconds should read 5s assert_eq!(timer.time(sec!(20)),sec!(5)); } #[test] fn test_timer()->Result<(),Error>{ //create a paused timer that reads 0s let mut timer=Timer::::paused(sec!(0),sec!(0)); //the paused timer at 1 second should read 0s assert_eq!(timer.time(sec!(1)),sec!(0)); //unpause it after one second timer.unpause(sec!(1))?; //the timer at 6 seconds should read 5s assert_eq!(timer.time(sec!(6)),sec!(5)); //pause the timer after 11 seconds timer.pause(sec!(11))?; //the paused timer at 20 seconds should read 10s assert_eq!(timer.time(sec!(20)),sec!(10)); Ok(()) } }