odem-rs-core 0.1.0

Core components of the ODEM-rs simulation framework
use core::cmp::Reverse;

use intrusive_collections::KeyAdapter;

use crate::{
	calendar::{IdleOnDrop, Scheduler, ordering::ForceOrd},
	config::Config,
	continuation::{Adapter, Continuation},
	fsm::Brand,
	simulator::{Mark, Prec},
};

/// Intrusive collections adapter that sorts continuations according to
/// activation time.
pub(super) struct TimeKey<C: ?Sized + Config>(pub Adapter<C, IdleOnDrop<C>>);

/// Intrusive collections adapter that stably sorts continuations according to
/// agent rank and job precedence.
pub(super) struct RankKey<C: ?Sized + Config>(pub Adapter<C, IdleOnDrop<C>>);

crate::intrusive_adapter_newtype!(TimeKey, RankKey);

impl<'a, C: ?Sized + Config> KeyAdapter<'a> for TimeKey<C>
where
	C::Plan: Scheduler<State = super::State<C>>,
{
	type Key = ForceOrd<C::Time>; // activation time

	#[inline]
	fn get_key(&self, cont: &'a Continuation<'static, C>) -> Self::Key {
		cont.brand(|inner, once| {
			let next = unsafe { inner.token(once).into_next().unwrap_unchecked() };
			inner.next_state(&next, |s| ForceOrd(s.time))
		})
	}
}

impl<'a, C: ?Sized + Config> KeyAdapter<'a> for RankKey<C>
where
	C::Plan: Scheduler<State = super::State<C>>,
{
	type Key = (
		Reverse<C::Rank>, // agent rank
		Mark,             // agent mark
		Prec,             // job precedence
		u64,              // stability counter
	);

	#[inline]
	fn get_key(&self, cont: &'a Continuation<'static, C>) -> Self::Key {
		cont.brand(|inner, once| {
			let next = unsafe { inner.token(once).into_next().unwrap_unchecked() };

			inner.next_state(&next, |s| {
				(
					// Using the rank here is unproblematic, because we update
					// the ordering whenever the rank changes.
					Reverse(inner.branded_share(&next).rank()),
					inner.mark(&next).get(),
					// Using the precedence here is unproblematic, since it
					// cannot be changed after a task has been activated.
					inner.prec(),
					s.count,
				)
			})
		})
	}
}