use std::rc::{Rc,Weak};
use std::cell::RefCell;
use std::mem::{size_of};
use std::convert::TryInto;
use crate::{Phit,SimulationShared,SimulationMut};
use crate::topology::Location;
use crate::quantify::Quantifiable;
use crate::router::{AcknowledgeMessage};
use quantifiable_derive::Quantifiable;
pub type Time = u64;
pub trait Eventful
{
fn process(&mut self, simulation:&SimulationShared, simulation_mut:&mut SimulationMut) -> Vec<EventGeneration>;
fn as_eventful(&self)->Weak<RefCell<dyn Eventful>>;
fn schedule(&mut self, _current_cycle:Time, delay:Time) -> Option<EventGeneration>
{
let event = Event::Generic(self.as_eventful().upgrade().expect("missing component"));
Some(EventGeneration{
delay: delay,
position: CyclePosition::End,
event,
})
}
}
#[derive(Clone)]
pub enum Event
{
PhitToLocation{
phit: Rc<Phit>,
previous: Location,
new: Location,
},
Acknowledge{
location: Location,
message: AcknowledgeMessage,
},
Generic(Rc<RefCell<dyn Eventful>>),
}
impl Quantifiable for Event
{
fn total_memory(&self) -> usize
{
let mut total= size_of::<Self>();
match self
{
&Event::PhitToLocation{
ref phit,
previous: _,
new: _,
} => total+=phit.as_ref().total_memory(),
_ => (),
}
total
}
fn print_memory_breakdown(&self)
{
unimplemented!();
}
fn forecast_total_memory(&self) -> usize
{
unimplemented!();
}
}
pub enum CyclePosition
{
Begin,
End,
}
pub struct EventGeneration
{
pub delay: Time,
pub position: CyclePosition,
pub event: Event,
}
#[derive(Quantifiable)]
pub struct EventQueue
{
event_begin_circle: Vec<Vec<Event>>, event_end_circle: Vec<Vec<Event>>, current: usize,
}
impl EventQueue
{
pub fn new (size:usize) -> EventQueue
{
EventQueue{
event_begin_circle: vec![ vec![] ; size ],
event_end_circle: vec![ vec![] ; size ],
current:0,
}
}
pub fn advance(&mut self)
{
self.event_begin_circle[self.current]=Vec::new();
self.event_end_circle[self.current]=Vec::new();
self.current=(self.current+1)%self.event_begin_circle.len();
}
pub fn access_begin(&self, ievent:usize) -> Option<&Event>
{
let v=&self.event_begin_circle[self.current];
if ievent<v.len()
{
Some(&v[ievent])
}
else
{
None
}
}
pub fn access_end(&self, ievent:usize) -> Option<&Event>
{
let v=&self.event_end_circle[self.current];
if ievent<v.len()
{
Some(&v[ievent])
}
else
{
None
}
}
pub fn enqueue_begin(&mut self, event:Event, delay: Time)
{
let delay : usize = delay.try_into().unwrap();
if delay>=self.event_begin_circle.len()
{
panic!("Delay too long");
}
let position=(self.current+delay) % self.event_begin_circle.len();
self.event_begin_circle[position].push(event);
}
pub fn enqueue_end(&mut self, event:Event, delay: Time)
{
let delay : usize = delay.try_into().unwrap();
if delay>=self.event_end_circle.len()
{
panic!("Delay too long");
}
let position=(self.current+delay) % self.event_end_circle.len();
self.event_end_circle[position].push(event);
}
pub fn enqueue(&mut self, event_generation:EventGeneration)
{
match event_generation.position
{
CyclePosition::Begin => self.enqueue_begin(event_generation.event,event_generation.delay),
CyclePosition::End => self.enqueue_end(event_generation.event,event_generation.delay),
};
}
}
pub fn next_multiple(x:Time, divisor:Time) -> Time
{
x - x.rem_euclid(divisor) + divisor
}
pub fn round_to_multiple(x:Time, divisor: Time) -> Time
{
next_multiple(x-1,divisor)
}
#[cfg(test)]
mod tests
{
use super::*;
#[test]
fn multiples()
{
assert_eq!( next_multiple(10,5) , 15 );
assert_eq!( next_multiple(2,5) , 5 );
assert_eq!( round_to_multiple(10,5) , 10 );
assert_eq!( round_to_multiple(12,5) , 15 );
}
}