use crate::link_ops::LinkOps;
use crate::pointer_ops::PointerOps;
pub unsafe trait Adapter {
type LinkOps: LinkOps;
type PointerOps: PointerOps;
unsafe fn get_value(
&self,
link: <Self::LinkOps as LinkOps>::LinkPtr,
) -> *const <Self::PointerOps as PointerOps>::Value;
unsafe fn get_link(
&self,
value: *const <Self::PointerOps as PointerOps>::Value,
) -> <Self::LinkOps as LinkOps>::LinkPtr;
fn link_ops(&self) -> &Self::LinkOps;
fn link_ops_mut(&mut self) -> &mut Self::LinkOps;
fn pointer_ops(&self) -> &Self::PointerOps;
}
#[macro_export]
macro_rules! container_of {
($ptr:expr, $container:path, $field:ident) => {
#[allow(clippy::cast_ptr_alignment)]
{
($ptr as *const _ as *const u8).sub($crate::offset_of!($container, $field))
as *const $container
}
};
}
#[macro_export]
macro_rules! intrusive_adapter {
(@impl
$(#[$attr:meta])* $vis:vis $name:ident ($($args:tt),*)
= $pointer:ty: $value:path { $field:ident: $link:ty } $($where_:tt)*
) => {
#[allow(explicit_outlives_requirements)]
$(#[$attr])*
$vis struct $name<$($args),*> $($where_)* {
link_ops: <$link as $crate::DefaultLinkOps>::Ops,
pointer_ops: $crate::DefaultPointerOps<$pointer>,
}
unsafe impl<$($args),*> Send for $name<$($args),*> $($where_)* {}
unsafe impl<$($args),*> Sync for $name<$($args),*> $($where_)* {}
impl<$($args),*> Copy for $name<$($args),*> $($where_)* {}
impl<$($args),*> Clone for $name<$($args),*> $($where_)* {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<$($args),*> Default for $name<$($args),*> $($where_)* {
#[inline]
fn default() -> Self {
Self::NEW
}
}
#[allow(dead_code)]
impl<$($args),*> $name<$($args),*> $($where_)* {
pub const NEW: Self = $name {
link_ops: <$link as $crate::DefaultLinkOps>::NEW,
pointer_ops: $crate::DefaultPointerOps::<$pointer>::new(),
};
#[inline]
pub fn new() -> Self {
Self::NEW
}
}
#[allow(dead_code, unsafe_code)]
unsafe impl<$($args),*> $crate::Adapter for $name<$($args),*> $($where_)* {
type LinkOps = <$link as $crate::DefaultLinkOps>::Ops;
type PointerOps = $crate::DefaultPointerOps<$pointer>;
#[inline]
unsafe fn get_value(&self, link: <Self::LinkOps as $crate::LinkOps>::LinkPtr) -> *const <Self::PointerOps as $crate::PointerOps>::Value {
$crate::container_of!(link.as_ptr(), $value, $field)
}
#[inline]
unsafe fn get_link(&self, value: *const <Self::PointerOps as $crate::PointerOps>::Value) -> <Self::LinkOps as $crate::LinkOps>::LinkPtr {
let ptr = (value as *const u8).add($crate::offset_of!($value, $field));
core::ptr::NonNull::new_unchecked(ptr as *mut _)
}
#[inline]
fn link_ops(&self) -> &Self::LinkOps {
&self.link_ops
}
#[inline]
fn link_ops_mut(&mut self) -> &mut Self::LinkOps {
&mut self.link_ops
}
#[inline]
fn pointer_ops(&self) -> &Self::PointerOps {
&self.pointer_ops
}
}
};
(@find_generic
$(#[$attr:meta])* $vis:vis $name:ident ($($prev:tt)*) > $($rest:tt)*
) => {
intrusive_adapter!(@impl
$(#[$attr])* $vis $name ($($prev)*) $($rest)*
);
};
(@find_generic
$(#[$attr:meta])* $vis:vis $name:ident ($($prev:tt)*) $cur:tt $($rest:tt)*
) => {
intrusive_adapter!(@find_generic
$(#[$attr])* $vis $name ($($prev)* $cur) $($rest)*
);
};
(@find_if_generic
$(#[$attr:meta])* $vis:vis $name:ident < $($rest:tt)*
) => {
intrusive_adapter!(@find_generic
$(#[$attr])* $vis $name () $($rest)*
);
};
(@find_if_generic
$(#[$attr:meta])* $vis:vis $name:ident $($rest:tt)*
) => {
intrusive_adapter!(@impl
$(#[$attr])* $vis $name () $($rest)*
);
};
($(#[$attr:meta])* $vis:vis $name:ident $($rest:tt)*) => {
intrusive_adapter!(@find_if_generic
$(#[$attr])* $vis $name $($rest)*
);
};
}
#[cfg(test)]
mod tests {
use crate::LinkedListLink;
use std::rc::Rc;
struct Obj {
link: LinkedListLink,
}
#[deny(missing_docs)]
intrusive_adapter! {
ObjAdapter1 = Rc<Obj>: Obj { link: LinkedListLink }
}
}