forked from StrafesNET/strafe-client
180 lines
3.6 KiB
Rust
180 lines
3.6 KiB
Rust
|
use strafesnet_common::integer::{Time,Ratio64};
|
||
|
|
||
|
pub trait TimerState:Copy{
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
#[derive(Clone,Copy,Debug)]
|
||
|
struct Scaled{
|
||
|
scale:Ratio64,
|
||
|
offset:Time,
|
||
|
}
|
||
|
impl Scaled{
|
||
|
fn scale(&self,time:Time)->Time{
|
||
|
Time::raw(self.scale.mul_int(time.get()))
|
||
|
}
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
impl TimerState for Scaled{
|
||
|
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)]
|
||
|
struct Realtime{
|
||
|
offset:Time,
|
||
|
}
|
||
|
impl TimerState for Realtime{
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Clone,Debug)]
|
||
|
pub struct Timer<T>{
|
||
|
state:T,
|
||
|
paused:bool,
|
||
|
}
|
||
|
|
||
|
impl Timer<Realtime>{
|
||
|
pub fn realtime(offset:Time)->Self{
|
||
|
Self{
|
||
|
state:Realtime{offset},
|
||
|
paused:false,
|
||
|
}
|
||
|
}
|
||
|
pub fn realtime_paused(offset:Time)->Self{
|
||
|
Self{
|
||
|
state:Realtime{offset},
|
||
|
paused:true,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[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{}
|
||
|
|
||
|
impl Timer<Scaled>{
|
||
|
pub fn scaled(scale:Ratio64,offset:Time)->Self{
|
||
|
Self{
|
||
|
state:Scaled{scale,offset},
|
||
|
paused:false,
|
||
|
}
|
||
|
}
|
||
|
pub fn scaled_paused(scale:Ratio64,offset:Time)->Self{
|
||
|
Self{
|
||
|
state:Scaled{scale,offset},
|
||
|
paused:true,
|
||
|
}
|
||
|
}
|
||
|
pub fn get_scale(&mut self)->Ratio64{
|
||
|
self.state.get_scale()
|
||
|
}
|
||
|
pub fn set_scale(&mut self,time:Time,new_scale:Ratio64){
|
||
|
self.state.set_scale(time,new_scale)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T:TimerState> Timer<T>{
|
||
|
pub fn time(&self,time:Time)->Time{
|
||
|
match self.paused{
|
||
|
true=>self.state.get_offset(),
|
||
|
false=>self.state.get_time(time),
|
||
|
}
|
||
|
}
|
||
|
pub fn set_time(&mut self,time:Time,new_time:Time){
|
||
|
match self.paused{
|
||
|
true=>self.state.set_offset(new_time),
|
||
|
false=>self.state.set_time(time,new_time),
|
||
|
}
|
||
|
}
|
||
|
pub fn pause(&mut self,time:Time)->Result<(),Error>{
|
||
|
match self.paused{
|
||
|
true=>Err(Error::AlreadyPaused),
|
||
|
false=>{
|
||
|
let new_time=self.time(time);
|
||
|
self.state.set_offset(new_time);
|
||
|
self.paused=true;
|
||
|
Ok(())
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
pub fn unpause(&mut self,time:Time)->Result<(),Error>{
|
||
|
match self.paused{
|
||
|
true=>{
|
||
|
let new_time=self.time(time);
|
||
|
self.state.set_time(time,new_time);
|
||
|
self.paused=false;
|
||
|
Ok(())
|
||
|
},
|
||
|
false=>Err(Error::AlreadyUnpaused),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#[cfg(test)]
|
||
|
mod test{
|
||
|
use super::{Time,Timer,Error};
|
||
|
macro_rules! sec {
|
||
|
($s: expr) => {
|
||
|
Time::from_secs($s)
|
||
|
};
|
||
|
}
|
||
|
#[test]
|
||
|
fn test_timer()->Result<(),Error>{
|
||
|
//create a paused timer that reads 0s
|
||
|
let mut timer=Timer::realtime_paused(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(())
|
||
|
}
|
||
|
}
|