odem-rs-core 0.3.0

Core components of the odem-rs simulation framework
Documentation
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 = match inner.token(once).into_next() {
				Ok(next) => next,
				#[cfg(debug_assertions)]
				Err(err) => panic!("{}", err),
				#[cfg(not(debug_assertions))]
				_ => unsafe { core::hint::unreachable_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 = match inner.token(once).into_next() {
				Ok(next) => next,
				#[cfg(debug_assertions)]
				Err(err) => panic!("{}", err),
				#[cfg(not(debug_assertions))]
				_ => unsafe { core::hint::unreachable_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,
				)
			})
		})
	}
}