use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::NonNull;
use crate::rcu::callback::{RcuCallFn, RcuDeferFn};
use crate::rcu::context::{RcuContext, RcuDeferContext, RcuReadContext};
use crate::rcu::flavor::RcuFlavor;
use crate::utility::*;
#[must_use]
pub unsafe trait RcuRef<F> {
type Output;
unsafe fn take_ownership_unchecked(self) -> Self::Output;
fn take_ownership<C>(self, context: &mut C) -> Self::Output
where
Self: Sized,
C: RcuContext<Flavor = F>,
{
context.rcu_synchronize();
unsafe { self.take_ownership_unchecked() }
}
fn defer_cleanup<C>(self, context: &mut C)
where
Self: Sized,
C: RcuDeferContext<Flavor = F>,
{
context.rcu_defer(RcuDeferFn::<_, F>::new(move || {
unsafe {
self.take_ownership_unchecked();
}
}))
}
fn call_cleanup<C>(self, context: &C)
where
Self: Sized + Send + 'static,
C: RcuReadContext<Flavor = F> + 'static,
{
context.rcu_call(RcuCallFn::new(move || {
unsafe {
self.take_ownership_unchecked();
}
}));
}
fn safe_cleanup(self)
where
Self: Sized + Send + 'static,
F: RcuFlavor,
{
F::rcu_cleanup(Box::new(move |context| {
context.rcu_synchronize();
unsafe {
self.take_ownership_unchecked();
}
}));
}
}
unsafe impl<T, F> RcuRef<F> for Option<T>
where
T: RcuRef<F>,
{
type Output = Option<T::Output>;
unsafe fn take_ownership_unchecked(self) -> Self::Output {
self.map(|r| r.take_ownership_unchecked())
}
}
unsafe impl<T, F> RcuRef<F> for Vec<T>
where
T: RcuRef<F>,
{
type Output = Vec<T::Output>;
unsafe fn take_ownership_unchecked(self) -> Self::Output {
self.into_iter()
.map(|r| r.take_ownership_unchecked())
.collect()
}
}
macro_rules! impl_rcu_ref_for_tuple {
($($x:literal),*) => {
paste::paste!{
unsafe impl<$([<T $x>]),*, F> RcuRef<F> for ($([<T $x>]),*)
where
$([<T $x>]: RcuRef<F>),*,
{
type Output = ($([<T $x>]::Output),*,);
unsafe fn take_ownership_unchecked(self) -> Self::Output {
(
$(self.$x.take_ownership_unchecked()),*,
)
}
}
}
};
}
impl_rcu_ref_for_tuple!(0, 1);
impl_rcu_ref_for_tuple!(0, 1, 2);
impl_rcu_ref_for_tuple!(0, 1, 2, 3);
impl_rcu_ref_for_tuple!(0, 1, 2, 3, 4);
impl_rcu_ref_for_tuple!(0, 1, 2, 3, 4, 5);
impl_rcu_ref_for_tuple!(0, 1, 2, 3, 4, 5, 6);
pub struct BoxRefOwned<T>(Box<T>);
impl<T> Deref for BoxRefOwned<T>
where
T: Deref,
{
type Target = T::Target;
fn deref(&self) -> &Self::Target {
self.0.deref().deref()
}
}
unsafe impl<T: Send> Send for BoxRefOwned<T> {}
unsafe impl<T: Sync> Sync for BoxRefOwned<T> {}
pub struct RcuRefBox<T, F>
where
T: Send + 'static,
F: RcuFlavor + 'static,
{
ptr: *mut T,
_unsend: PhantomUnsend<(T, F)>,
_unsync: PhantomUnsync<(T, F)>,
}
impl<T, F> RcuRefBox<T, F>
where
T: Send,
F: RcuFlavor,
{
pub(crate) fn new(ptr: NonNull<T>) -> Self {
Self {
ptr: ptr.as_ptr(),
_unsend: PhantomData,
_unsync: PhantomData,
}
}
}
unsafe impl<T, F> RcuRef<F> for RcuRefBox<T, F>
where
T: Send,
F: RcuFlavor,
{
type Output = BoxRefOwned<T>;
unsafe fn take_ownership_unchecked(mut self) -> Self::Output {
let output = BoxRefOwned(Box::from_raw(self.ptr));
self.ptr = std::ptr::null_mut();
output
}
}
unsafe impl<T, F> Send for RcuRefBox<T, F>
where
T: Send,
F: RcuFlavor,
{
}
impl<T, F> Drop for RcuRefBox<T, F>
where
T: Send + 'static,
F: RcuFlavor + 'static,
{
fn drop(&mut self) {
if let Some(ptr) = NonNull::new(self.ptr) {
Self::new(ptr).safe_cleanup();
}
}
}
impl<T, F> Deref for RcuRefBox<T, F>
where
T: Send + Deref,
F: RcuFlavor,
{
type Target = T::Target;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref_unchecked().deref() }
}
}
mod asserts {
use super::*;
use static_assertions::{assert_impl_all, assert_not_impl_all};
use crate::rcu::default::RcuDefaultFlavor;
use crate::utility::asserts::*;
mod rcu_ref {
use super::*;
assert_impl_all!(RcuRefBox<SendButNotSync, RcuDefaultFlavor>: Send);
assert_not_impl_all!(RcuRefBox<SendButNotSync, RcuDefaultFlavor>: Sync);
assert_impl_all!(RcuRefBox<SendAndSync, RcuDefaultFlavor>: Send);
assert_not_impl_all!(RcuRefBox<SendAndSync, RcuDefaultFlavor>: Sync);
}
mod rcu_ref_owned {
use super::*;
assert_not_impl_all!(BoxRefOwned<NotSendNotSync>: Send);
assert_not_impl_all!(BoxRefOwned<NotSendNotSync>: Sync);
assert_impl_all!(BoxRefOwned<SendButNotSync>: Send);
assert_not_impl_all!(BoxRefOwned<SendButNotSync>: Sync);
assert_not_impl_all!(BoxRefOwned<NotSendButSync>: Send);
assert_impl_all!(BoxRefOwned<NotSendButSync>: Sync);
assert_impl_all!(BoxRefOwned<SendAndSync>: Send);
assert_impl_all!(BoxRefOwned<SendAndSync>: Sync);
}
}