caminos-lib 0.5.2

A modular interconnection network simulator.
Documentation
/*!

Representations of data before and while in the network.

+ A [Message] is a data message generated by a server with destination towards another server. It is at application level, to inject it into the network it must be broken into packets.
+ A [Packet] is a block of data that follows some route from its source to its destination. Its size is measured in phits.
+ A [Phit], or physical digit, is the smallest unit of data we represent. Specifically, if several phits are in a buffer, only one of them will be able to move out in a cycle.

Is not given a datatype to the so called flit, or flow-control digit. What is a flit is defined by the employed router.

*/

pub use quantifiable_derive::Quantifiable;//the derive macro

use std::rc::Rc;
use std::cell::RefCell;
use std::ops::Deref;

use crate::routing::RoutingInfo;

///Minimal unit to be processed by the network.
///Not to be confused with flits.
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Phit
{
	///The packet to what this phit belongs
	pub packet: PacketRef,
	///position inside the packet
	pub index: usize,
	///The virtual channel in which this phit should be inserted
	pub virtual_channel: RefCell<Option<usize>>,
}


#[derive(Quantifiable)]
#[derive(Debug,Default)]
pub struct PacketExtraInfo
{
	pub link_classes: Vec<usize>,
	pub entry_virtual_channels: Vec<Option<usize>>,
	pub cycle_per_hop: Vec<usize>,
}

///A portion of a message. They are divided into phits.
///All phits must go through the same queues without phits of other packets in between.
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Packet
{
	///Number of phits
	pub size: usize,
	///Information for the routing
	pub routing_info: RefCell<RoutingInfo>,
	///The message to what this packet belongs.
	pub message: Rc<Message>,
	///position inside the message
	pub index: usize,
	///The cycle when the packet has touched the first router. This is, the packet leading phit has been inserted into a router.
	///We set it to 0 if the packet has not entered the network yet.
	pub cycle_into_network: RefCell<usize>,
	///Extra info tracked for some special statistics.
	pub extra: RefCell<Option<PacketExtraInfo>>,
}

#[cfg(feature="slab_packet")]
thread_local!{
	static PACKET_SLAB : RefCell<slab::Slab<Packet>> = RefCell::new(slab::Slab::new());
}

impl Packet
{
	#[cfg(not(any(feature="raw_packet",feature="slab_packet")))]
	pub fn into_ref(self) -> PacketRef {
		PacketRef{inner:Rc::new(self)}
	}
	#[cfg(feature="raw_packet")]
	pub fn into_ref(self) -> PacketRef {
		let packet = Box::into_raw(Box::new(self));
		let inner = PacketRefInner{ packet };
		PacketRef {
			inner
		}
	}
	#[cfg(feature="slab_packet")]
	pub fn into_ref(self) -> PacketRef {
		let packet = PACKET_SLAB.with(|slab| {slab.borrow_mut().insert(self) });
		let inner = PacketRefInner{ packet };
		PacketRef {
			inner
		}
	}
}

///An application message, broken into packets
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Message
{
	///Server that created the message.
	pub origin: usize,
	///Server that is the destination of the message.
	pub destination: usize,
	///Number of phits.
	pub size: usize,
	///Cycle when the message was created.
	pub creation_cycle: usize,
}

impl Phit
{
	///Whether the phit is leading a packet. Routers check this to make requests, stablish flows, etc.
	pub fn is_begin(&self) -> bool
	{
		self.index==0
	}
	///Whether this phit is the last one of a packet. Routers use this to finalize some operations.
	pub fn is_end(&self) -> bool
	{
		self.index==self.packet.size-1
	}
}


#[derive(Debug,Clone,Quantifiable)]
pub struct PacketRef {
	inner: PacketRefInner
}

impl PacketRef
{
	/**
	To be called when the last phit is deallocated so we may deallocate the whole packet.
	It is a NOP when using `Rc<Packet>` but important when `feature=raw_packet`.
	**/
	#[cfg(not(any(feature="raw_packet",feature="slab_packet")))]
	pub fn destroy(&self)
	{
	}
	#[cfg(feature="raw_packet")]
	pub fn destroy(&self)
	{
		let _boxed = unsafe { Box::from_raw(self.inner.packet as *mut Packet) };
	}
	#[cfg(feature="slab_packet")]
	pub fn destroy(&self)
	{
		let _packet = PACKET_SLAB.with(|slab|slab.borrow_mut().remove(self.inner.packet));
	}
}



//#[cfg(feature="rc_packet")]
#[cfg(not(any(feature="raw_packet",feature="slab_packet")))]
pub type PacketRefInner = Rc<Packet>;

#[cfg(feature="raw_packet")]
#[derive(Debug,Clone,Quantifiable)]
pub struct PacketRefInner {
	packet: *const Packet,
}

#[cfg(feature="slab_packet")]
#[derive(Debug,Clone,Quantifiable)]
pub struct PacketRefInner {
	packet: usize,
}

impl Deref for PacketRef {
	type Target = Packet;
	#[cfg(not(any(feature="raw_packet",feature="slab_packet")))]
	fn deref(&self) -> &<Self as Deref>::Target
	{
		&*self.inner
	}
	#[cfg(feature="raw_packet")]
	fn deref(&self) -> &<Self as Deref>::Target
	{
		unsafe {
			&*self.inner.packet
		}
	}
	#[cfg(feature="slab_packet")]
	fn deref(&self) -> &<Self as Deref>::Target
	{
		//PACKET_SLAB.with(|slab|slab.get(self.inner.packet).expect("The packet is not in the slab."))
		let packet = self.inner.packet;
		//let f : dyn for<'a> FnOnce(&'a slab::Slab<Packet>)->&'a Packet = |slab:&slab::Slab<Packet>|slab.get(packet).expect("The packet is not in the slab.");
		//fn aux(slab: &'static slab::Slab<Packet>, packet:usize) -> &'static Packet
		//{
		//	slab.get(packet).expect("The packet is not in the slab.")
		//}
		//let ref_packet: &'static Packet = PACKET_SLAB.with(|slab|aux(slab,packet));
		let pt_packet: *const Packet = PACKET_SLAB.with(|slab|slab.borrow().get(packet).expect("The packet is not in the slab.") as *const Packet);
		unsafe {
			// The reference is valid until calling destroy.
			&*pt_packet
		}
	}
}

impl AsRef<Packet> for PacketRef {
	fn as_ref(&self) -> &Packet { &*self }
}