odem-rs-core 0.3.0

Core components of the odem-rs simulation framework
Documentation
use core::{marker::PhantomData, mem::offset_of, ptr::NonNull};

use intrusive_collections::{DefaultLinkOps, LinkOps};

use super::{Continuation, Link};

use crate::{
	config::Config,
	ptr::{IntrusivelyCounted, Irc},
};

/* ******************************************************** Intrusive Adapter */

/// Adapter for [continuations] to be inserted into intrusive data structures.
///
/// [continuations]: Continuation
pub struct Adapter<C: ?Sized + Config, P = Irc<Continuation<'static, C>>> {
	/// The link ops for the chosen link type.
	link_ops: <Link as DefaultLinkOps>::Ops,
	/// The [pointer ops] for `Irc` of [continuations].
	///
	/// [pointer ops]: PointerOps
	/// [continuations]: Continuation
	pointer_ops: PointerOps<Continuation<'static, C>, P>,
}

impl<C: ?Sized + Config, P> Adapter<C, P> {
	/// The associated constant that represents `Link::default()`.
	///
	/// This exists because `Default::default()` is not a constant function.
	pub const NEW: Self = Adapter {
		link_ops: <Link as DefaultLinkOps>::NEW,
		pointer_ops: PointerOps(PhantomData),
	};
}

impl<C: ?Sized + Config, P> Default for Adapter<C, P> {
	fn default() -> Self {
		Self::NEW
	}
}

impl<C: ?Sized + Config, P> Clone for Adapter<C, P> {
	fn clone(&self) -> Self {
		*self
	}
}

impl<C: ?Sized + Config, P> Copy for Adapter<C, P> {}

unsafe impl<C, P> intrusive_collections::Adapter for Adapter<C, P>
where
	C: ?Sized + Config,
	P: From<Irc<Continuation<'static, C>>> + Into<Irc<Continuation<'static, C>>>,
{
	type LinkOps = <Link as DefaultLinkOps>::Ops;
	type PointerOps = PointerOps<Continuation<'static, C>, P>;

	unsafe fn get_value(
		&self,
		link: <Self::LinkOps as LinkOps>::LinkPtr,
	) -> *const Continuation<'static, C> {
		intrusive_collections::container_of!(link.as_ptr(), Continuation<'static, C>, hook)
	}

	unsafe fn get_link(
		&self,
		value: *const Continuation<'static, C>,
	) -> <Self::LinkOps as LinkOps>::LinkPtr {
		unsafe {
			let ptr = (value as *const u8).add(offset_of!(Continuation<'static, C>, hook));
			NonNull::new_unchecked(ptr as *mut _)
		}
	}

	fn link_ops(&self) -> &Self::LinkOps {
		&self.link_ops
	}

	fn link_ops_mut(&mut self) -> &mut Self::LinkOps {
		&mut self.link_ops
	}

	fn pointer_ops(&self) -> &Self::PointerOps {
		&self.pointer_ops
	}
}

/// Another helper structure that helps with the conversion between raw
/// [Continuation] pointers and owned ones.
pub struct PointerOps<V, P>(PhantomData<(V, P)>);

impl<V, P> PointerOps<V, P> {
	/// Default instance of pointer ops.
	pub const NEW: Self = PointerOps(PhantomData);
}

impl<V, P> Clone for PointerOps<V, P> {
	fn clone(&self) -> Self {
		*self
	}
}

impl<V, P> Copy for PointerOps<V, P> {}

unsafe impl<V, P> intrusive_collections::PointerOps for PointerOps<V, P>
where
	V: IntrusivelyCounted,
	P: From<Irc<V>> + Into<Irc<V>>,
{
	type Value = V;
	type Pointer = P;

	unsafe fn from_raw(&self, value: *const V) -> P {
		unsafe { P::from(Irc::from_raw(NonNull::new_unchecked(value as *mut V))) }
	}

	fn into_raw(&self, ptr: P) -> *const V {
		Irc::into_raw(P::into(ptr)).as_ptr() as *const V
	}
}

/// Helper macro to generate an implementation for a wrapper
/// [`Adapter`](intrusive_collections::Adapter) based on the [`Adapter`] for
/// `Continuations`.
///
/// This helps to fit continuations into custom event calendars.
#[macro_export]
#[doc(hidden)]
macro_rules! intrusive_adapter_newtype {
	() => {};

	($name:ident) => {
		unsafe impl<C: ?Sized + Config> ::intrusive_collections::Adapter for $name<C> {
			type LinkOps = <$crate::continuation::Adapter<C, $crate::calendar::IdleOnDrop<C>> as ::intrusive_collections::Adapter>::LinkOps;
			type PointerOps = <$crate::continuation::Adapter<C, $crate::calendar::IdleOnDrop<C>> as ::intrusive_collections::Adapter>::PointerOps;

			#[inline]
			unsafe fn get_value(&self, link: <Self::LinkOps as ::intrusive_collections::LinkOps>::LinkPtr) -> *const <Self::PointerOps as ::intrusive_collections::PointerOps>::Value {
				unsafe { self.0.get_value(link) }
			}

			#[inline]
			unsafe fn get_link(&self, value: *const <Self::PointerOps as ::intrusive_collections::PointerOps>::Value) -> <Self::LinkOps as ::intrusive_collections::LinkOps>::LinkPtr {
				unsafe { self.0.get_link(value) }
			}

			#[inline]
			fn link_ops(&self) -> &Self::LinkOps {
				self.0.link_ops()
			}

			#[inline]
			fn link_ops_mut(&mut self) -> &mut Self::LinkOps {
				self.0.link_ops_mut()
			}

			#[inline]
			fn pointer_ops(&self) -> &Self::PointerOps {
				self.0.pointer_ops()
			}
		}
	};

	($name:ident, $($tail:ident),*) => {
		$crate::intrusive_adapter_newtype!($name);
		$crate::intrusive_adapter_newtype!($($tail),*);
	};

	($($name:ident,)+) => {
		$crate::intrusive_adapter_newtype!($($name),*);
	};
}