use std::{
cmp::{Ordering, Reverse},
collections::BinaryHeap,
};
use bytemuck::{Pod, Zeroable};
use mesocarp::comms::buses::Message;
use mesocarp::scheduling::{htw::Clock, Scheduleable};
use crate::AikaError;
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct Msg<T: Clone> {
pub from: (usize, usize),
pub to: (usize, usize),
pub sent: u64,
pub recv: u64,
pub data: T,
}
impl<T: Clone> Msg<T> {
pub fn new(data: T, sent: u64, recv: u64, sender_id: usize, target_actor: usize) -> Self {
Self {
from: (usize::MAX, sender_id),
to: (usize::MAX, target_actor),
sent,
recv,
data,
}
}
}
impl<T: Clone> Scheduleable for Msg<T> {
fn time(&self) -> u64 {
self.recv
}
fn commit_time(&self) -> u64 {
self.sent
}
}
impl<T: Clone> PartialOrd for Msg<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: Clone> PartialEq for Msg<T> {
fn eq(&self, other: &Self) -> bool {
self.from == other.from
&& self.to == other.to
&& self.sent == other.sent
&& self.recv == other.recv
}
}
impl<T: Clone> Eq for Msg<T> {}
impl<T: Clone> Ord for Msg<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.recv
.cmp(&other.recv)
.then_with(|| self.sent.cmp(&other.sent))
.then_with(|| self.from.cmp(&other.from))
.then_with(|| self.to.cmp(&other.to))
}
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub(crate) struct AntiMsg {
pub(crate) sent: u64,
pub(crate) received: u64,
pub(crate) from: (usize, usize),
pub(crate) to: (usize, usize),
}
impl AntiMsg {
pub fn new(sent: u64, received: u64, from: (usize, usize), to: (usize, usize)) -> Self {
AntiMsg {
sent,
received,
from,
to,
}
}
pub fn annihilate<T: Clone>(&self, other: &Msg<T>) -> bool {
self.sent == other.sent
&& self.received == other.recv
&& self.from == other.from
&& self.to == other.to
}
}
impl PartialEq for AntiMsg {
fn eq(&self, other: &Self) -> bool {
self.sent == other.sent && self.received == other.received
}
}
impl Eq for AntiMsg {}
impl PartialOrd for AntiMsg {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AntiMsg {
fn cmp(&self, other: &Self) -> Ordering {
self.received.partial_cmp(&other.received).unwrap()
}
}
impl Scheduleable for AntiMsg {
fn time(&self) -> u64 {
self.received
}
fn commit_time(&self) -> u64 {
self.sent
}
}
unsafe impl Pod for AntiMsg {}
unsafe impl Zeroable for AntiMsg {}
#[derive(Debug, Clone, Copy)]
pub(crate) enum Transfer<T: Pod + Zeroable + Clone> {
Msg(Msg<T>),
AntiMsg(AntiMsg),
}
impl<T: Pod + Zeroable + Clone> Message for Transfer<T> {
fn from(&self) -> usize {
match self {
Transfer::Msg(msg) => msg.from.0,
Transfer::AntiMsg(anti_msg) => anti_msg.from.0,
}
}
fn to(&self) -> Option<usize> {
match self {
Transfer::Msg(msg) => Some(msg.to.0),
Transfer::AntiMsg(anti_msg) => Some(anti_msg.to.0),
}
}
}
impl<T: Pod + Zeroable + Clone> Transfer<T> {
pub fn actor_from(&self) -> usize {
match self {
Transfer::Msg(msg) => msg.from.1,
Transfer::AntiMsg(anti_msg) => anti_msg.from.1,
}
}
pub fn actor_to(&self) -> usize {
match self {
Transfer::Msg(msg) => msg.to.1,
Transfer::AntiMsg(anti_msg) => anti_msg.to.1,
}
}
}
impl<T: Pod + Zeroable + Clone> Scheduleable for Transfer<T> {
fn time(&self) -> u64 {
match self {
Transfer::Msg(msg) => msg.time(),
Transfer::AntiMsg(anti_msg) => anti_msg.time(),
}
}
fn commit_time(&self) -> u64 {
match self {
Transfer::Msg(msg) => msg.commit_time(),
Transfer::AntiMsg(anti_msg) => anti_msg.commit_time(),
}
}
}
impl<T: Pod + Zeroable + Clone> PartialOrd for Transfer<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: Pod + Zeroable + Clone> PartialEq for Transfer<T> {
fn eq(&self, other: &Self) -> bool {
self.from() == other.from()
&& self.to() == other.to()
&& self.commit_time() == other.commit_time()
&& self.time() == other.time()
}
}
impl<T: Pod + Zeroable + Clone> Eq for Transfer<T> {}
impl<T: Pod + Zeroable + Clone> Ord for Transfer<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.time().cmp(&other.time())
}
}
unsafe impl<T: Pod + Zeroable + Clone> Send for Transfer<T> {}
unsafe impl<T: Pod + Zeroable + Clone> Sync for Transfer<T> {}
#[derive(Copy, Clone, Debug)]
pub enum SchedulingTask {
Timeout(u64),
Schedule(u64),
Trigger { time: u64, idx: usize },
Wait,
Break,
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct Event {
pub time: u64,
pub commit_time: u64,
pub actor: usize,
pub task: SchedulingTask,
}
impl Event {
pub fn new(commit_time: u64, time: u64, actor: usize, task: SchedulingTask) -> Self {
Self {
commit_time,
time,
actor,
task,
}
}
pub fn time(&self) -> u64 {
self.time
}
}
impl PartialEq for Event {
fn eq(&self, other: &Self) -> bool {
self.time == other.time
}
}
impl Eq for Event {}
impl PartialOrd for Event {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Event {
fn cmp(&self, other: &Self) -> Ordering {
self.time.partial_cmp(&other.time).unwrap()
}
}
impl Scheduleable for Event {
fn time(&self) -> u64 {
self.time
}
fn commit_time(&self) -> u64 {
self.commit_time
}
}
unsafe impl Zeroable for Event {}
unsafe impl Pod for Event {}
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
#[derive(Debug)]
pub struct LocalScheduler<const CLOCK_BW: usize, const CLOCK_SCALES: usize, T: Scheduleable> {
pub(crate) overflow: BinaryHeap<Reverse<T>>,
pub(crate) clock: Clock<T, CLOCK_BW, CLOCK_SCALES>,
}
impl<const CLOCK_BW: usize, const CLOCK_SCALES: usize, T: Scheduleable>
LocalScheduler<CLOCK_BW, CLOCK_SCALES, T>
{
pub fn new() -> Result<Self, AikaError> {
let overflow = BinaryHeap::new();
let clock = Clock::new()?;
Ok(Self { overflow, clock })
}
pub fn insert(&mut self, object: T) {
let possible_overflow = self.clock.insert(object);
if possible_overflow.is_err() {
let object = possible_overflow.err().unwrap();
self.overflow.push(Reverse(object));
}
}
pub fn now(&self) -> u64 {
self.clock.time
}
pub fn increment(&mut self) {
self.clock.increment(&mut self.overflow)
}
pub fn tick(&mut self) -> Result<Vec<T>, AikaError> {
Ok(self.clock.tick()?)
}
pub fn rollback(&mut self, time: u64) {
self.clock.rollback(&mut self.overflow, time)
}
}
unsafe impl<const CLOCK_SLOTS: usize, const CLOCK_HEIGHT: usize, T: Scheduleable> Send
for LocalScheduler<CLOCK_SLOTS, CLOCK_HEIGHT, T>
{
}
unsafe impl<const CLOCK_SLOTS: usize, const CLOCK_HEIGHT: usize, T: Scheduleable> Sync
for LocalScheduler<CLOCK_SLOTS, CLOCK_HEIGHT, T>
{
}