use super::ControlBlock;
#[cfg(feature = "multi_thread")]
use super::MTControlBlock;
use crate::list::{ListElement, ListEntry};
use crate::util::NonNull;
use std::cell::UnsafeCell;
use std::fmt;
use std::pin::Pin;
pub(super) struct EdgeTag;
pub(crate) struct Edge {
#[cfg(not(feature = "multi_thread"))]
destination: NonNull<ControlBlock>,
#[cfg(feature = "multi_thread")]
destination: Option<NonNull<ControlBlock>>,
link: UnsafeCell<ListEntry<Edge>>,
}
#[cfg(feature = "multi_thread")]
pub(crate) struct MTEdge {
destination: NonNull<MTControlBlock>,
link: UnsafeCell<ListEntry<MTEdge>>,
}
impl Edge {
#[inline]
#[allow(
clippy::missing_const_for_fn,
reason = "Const context makes no sense, edges are always heap-allocated."
)]
pub(crate) fn new(cb: Pin<&ControlBlock>) -> Self {
Edge {
#[cfg(not(feature = "multi_thread"))]
destination: NonNull::from_ref(cb.get_ref()),
#[cfg(feature = "multi_thread")]
destination: Some(NonNull::from_ref(cb.get_ref())),
link: UnsafeCell::new(ListEntry::default()),
}
}
#[cfg(feature = "multi_thread")]
#[inline]
#[allow(
clippy::missing_const_for_fn,
reason = "Const context makes no sense, edges are always heap-allocated."
)]
pub(crate) fn new_mt(_: Pin<&MTControlBlock>) -> Self {
Edge {
destination: None,
link: UnsafeCell::new(ListEntry::default()),
}
}
#[cfg(not(feature = "multi_thread"))]
#[inline]
#[allow(
clippy::missing_const_for_fn,
reason = "Const context makes no sense, edges are always heap-allocated."
)]
pub(super) fn get_control_block(&self) -> Pin<&ControlBlock> {
unsafe { Pin::new_unchecked(self.destination.as_ref()) }
}
#[cfg(feature = "multi_thread")]
#[inline]
#[allow(
clippy::missing_const_for_fn,
reason = "Const context makes no sense, edges are always heap-allocated."
)]
pub(super) fn get_control_block(&self) -> Option<Pin<&ControlBlock>> {
self.destination
.as_ref()
.map(|ptr| unsafe { Pin::new_unchecked(ptr.as_ref()) })
}
}
#[cfg(feature = "multi_thread")]
impl MTEdge {
#[inline]
#[allow(
clippy::missing_const_for_fn,
reason = "Const context makes no sense, edges are always heap-allocated."
)]
pub(crate) fn new(cb: Pin<&MTControlBlock>) -> Self {
MTEdge {
destination: NonNull::from_ref(cb.get_ref()),
link: UnsafeCell::new(ListEntry::default()),
}
}
#[inline]
#[allow(
clippy::missing_const_for_fn,
reason = "Const context makes no sense, edges are always heap-allocated."
)]
pub(super) fn get_control_block(&self) -> Pin<&MTControlBlock> {
unsafe { Pin::new_unchecked(self.destination.as_ref()) }
}
}
impl ListElement<EdgeTag> for Edge {
type Type = Edge;
#[inline]
fn get_entry(&self) -> &ListEntry<Self::Type> {
unsafe { &*self.link.get() }
}
#[inline]
fn get_entry_mut(&self) -> &mut ListEntry<Self::Type> {
unsafe { &mut *self.link.get() }
}
}
#[cfg(feature = "multi_thread")]
impl ListElement<EdgeTag> for MTEdge {
type Type = MTEdge;
#[inline]
fn get_entry(&self) -> &ListEntry<Self::Type> {
unsafe { &*self.link.get() }
}
#[inline]
fn get_entry_mut(&self) -> &mut ListEntry<Self::Type> {
unsafe { &mut *self.link.get() }
}
}
impl fmt::Debug for Edge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let mut d = f.debug_struct("Edge");
d.field("link", &self.link);
d.finish_non_exhaustive()
}
}
#[cfg(feature = "multi_thread")]
impl fmt::Debug for MTEdge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let mut d = f.debug_struct("MTEdge");
d.field("link", &self.link);
d.finish_non_exhaustive()
}
}
#[cfg(feature = "multi_thread")]
unsafe impl Send for MTEdge {}
#[cfg(feature = "multi_thread")]
unsafe impl Sync for MTEdge {}