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,Hash,Eq,PartialEq,PartialOrd,Debug)] enum Inner{} type InnerTime=Time; #[derive(Clone,Copy,Debug)] pub struct Realtime{ offset:InnerTime, _in:core::marker::PhantomData, _out:core::marker::PhantomData, } impl Realtime{ pub const fn new(offset:InnerTime)->Self{ Self{ offset, _in:core::marker::PhantomData, _out:core::marker::PhantomData, } } } #[derive(Clone,Copy,Debug)] pub struct Scaled{ scale:Ratio64, offset:InnerTime, _in:core::marker::PhantomData, _out:core::marker::PhantomData, } impl Scaled where Time:Copy, { pub const fn new(scale:Ratio64,offset:InnerTime)->Self{ Self{ scale, offset, _in:core::marker::PhantomData, _out:core::marker::PhantomData, } } const fn with_scale(scale:Ratio64)->Self{ Self::new(scale,InnerTime::ZERO) } const fn scale(&self,time:Time)->InnerTime{ InnerTime::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{ type In; type Out; fn identity()->Self; fn get_time(&self,time:Time)->Time; fn set_time(&mut self,time:Time,new_time:Time); fn get_offset(&self)->InnerTime; fn set_offset(&mut self,offset:InnerTime); } impl TimerState for Realtime{ type In=In; type Out=Out; fn identity()->Self{ Self::new(InnerTime::ZERO) } fn get_time(&self,time:Time)->Time{ time.coerce()+self.offset.coerce() } fn set_time(&mut self,time:Time,new_time:Time){ self.offset=new_time.coerce()-time.coerce(); } fn get_offset(&self)->InnerTime{ self.offset } fn set_offset(&mut self,offset:InnerTime){ self.offset=offset; } } impl TimerState for Scaled where Time:Copy, { type In=In; type Out=Out; fn identity()->Self{ Self::new(Ratio64::ONE,InnerTime::ZERO) } fn get_time(&self,time:Time)->Time{ (self.scale(time)+self.offset).coerce() } fn set_time(&mut self,time:Time,new_time:Time){ self.offset=new_time.coerce()-self.scale(time); } fn get_offset(&self)->InnerTime{ self.offset } fn set_offset(&mut self,offset:InnerTime){ self.offset=offset; } } #[derive(Clone,Copy,Debug)] pub struct TimerFixed{ state:T, _paused:P, } //scaled timer methods are generic across PauseState impl TimerFixed,P> where Time:Copy, { 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 where Time:Copy, { 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 where Time:Copy, { 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().coerce(), 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.coerce()), 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 where T:Copy, Time:Copy, { 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> where Time:Copy, { 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) }; } #[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)] enum Parent{} #[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)] enum Calculated{} #[test] fn test_timerfixed_scaled(){ //create a paused timer that reads 0s let timer=TimerFixed::,Paused>::from_state(Scaled::new(0.5f32.try_into().unwrap(),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(()) } }