use crate::sync::atomic::{self, Ordering};
#[cfg(feature = "std")]
use core::fmt;
pub(crate) use __private::Internal;
#[doc(hidden)]
pub trait NotificationPrivate {
type Tag;
fn fence(&self, internal: Internal);
fn is_additional(&self, internal: Internal) -> bool;
fn count(&self, internal: Internal) -> usize;
fn next_tag(&mut self, internal: Internal) -> Self::Tag;
}
pub trait Notification: NotificationPrivate {}
impl<N: NotificationPrivate + ?Sized> Notification for N {}
#[derive(Debug, Clone)]
#[doc(hidden)]
pub struct Notify(usize);
impl Notify {
fn new(count: usize) -> Self {
Self(count)
}
}
impl NotificationPrivate for Notify {
type Tag = ();
fn is_additional(&self, _: Internal) -> bool {
false
}
fn fence(&self, _: Internal) {
full_fence();
}
fn count(&self, _: Internal) -> usize {
self.0
}
fn next_tag(&mut self, _: Internal) -> Self::Tag {}
}
#[derive(Debug, Clone)]
#[doc(hidden)]
pub struct Additional<N: ?Sized>(N);
impl<N> Additional<N> {
fn new(inner: N) -> Self {
Self(inner)
}
}
impl<N> NotificationPrivate for Additional<N>
where
N: Notification + ?Sized,
{
type Tag = N::Tag;
fn is_additional(&self, _: Internal) -> bool {
true
}
fn fence(&self, i: Internal) {
self.0.fence(i);
}
fn count(&self, i: Internal) -> usize {
self.0.count(i)
}
fn next_tag(&mut self, i: Internal) -> Self::Tag {
self.0.next_tag(i)
}
}
#[derive(Debug, Clone)]
#[doc(hidden)]
pub struct Relaxed<N: ?Sized>(N);
impl<N> Relaxed<N> {
fn new(inner: N) -> Self {
Self(inner)
}
}
impl<N> NotificationPrivate for Relaxed<N>
where
N: Notification + ?Sized,
{
type Tag = N::Tag;
fn is_additional(&self, i: Internal) -> bool {
self.0.is_additional(i)
}
fn fence(&self, _: Internal) {
}
fn count(&self, i: Internal) -> usize {
self.0.count(i)
}
fn next_tag(&mut self, i: Internal) -> Self::Tag {
self.0.next_tag(i)
}
}
#[cfg(feature = "std")]
#[derive(Debug, Clone)]
#[doc(hidden)]
pub struct Tag<N: ?Sized, T> {
tag: T,
inner: N,
}
#[cfg(feature = "std")]
impl<N: ?Sized, T> Tag<N, T> {
fn new(tag: T, inner: N) -> Self
where
N: Sized,
{
Self { tag, inner }
}
}
#[cfg(feature = "std")]
impl<N, T> NotificationPrivate for Tag<N, T>
where
N: Notification + ?Sized,
T: Clone,
{
type Tag = T;
fn is_additional(&self, i: Internal) -> bool {
self.inner.is_additional(i)
}
fn fence(&self, i: Internal) {
self.inner.fence(i);
}
fn count(&self, i: Internal) -> usize {
self.inner.count(i)
}
fn next_tag(&mut self, _: Internal) -> Self::Tag {
self.tag.clone()
}
}
#[cfg(feature = "std")]
#[doc(hidden)]
pub struct TagWith<N: ?Sized, F> {
tag: F,
inner: N,
}
#[cfg(feature = "std")]
impl<N: fmt::Debug, F> fmt::Debug for TagWith<N, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Ellipses;
impl fmt::Debug for Ellipses {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("..")
}
}
f.debug_struct("TagWith")
.field("tag", &Ellipses)
.field("inner", &self.inner)
.finish()
}
}
#[cfg(feature = "std")]
impl<N, F> TagWith<N, F> {
fn new(tag: F, inner: N) -> Self {
Self { tag, inner }
}
}
#[cfg(feature = "std")]
impl<N, F, T> NotificationPrivate for TagWith<N, F>
where
N: Notification + ?Sized,
F: FnMut() -> T,
{
type Tag = T;
fn is_additional(&self, i: Internal) -> bool {
self.inner.is_additional(i)
}
fn fence(&self, i: Internal) {
self.inner.fence(i);
}
fn count(&self, i: Internal) -> usize {
self.inner.count(i)
}
fn next_tag(&mut self, _: Internal) -> Self::Tag {
(self.tag)()
}
}
#[derive(Debug)]
pub(crate) struct GenericNotify<F> {
count: usize,
additional: bool,
tags: F,
}
impl<T, F: TagProducer<Tag = T>> GenericNotify<F> {
pub(crate) fn new(count: usize, additional: bool, tags: F) -> Self {
Self {
count,
additional,
tags,
}
}
}
impl<T, F: TagProducer<Tag = T>> NotificationPrivate for GenericNotify<F> {
type Tag = T;
fn is_additional(&self, _: Internal) -> bool {
self.additional
}
fn fence(&self, _: Internal) {
}
fn count(&self, _: Internal) -> usize {
self.count
}
fn next_tag(&mut self, _: Internal) -> Self::Tag {
self.tags.next_tag()
}
}
pub(crate) trait TagProducer {
type Tag;
fn next_tag(&mut self) -> Self::Tag;
}
impl<T, F: FnMut() -> T> TagProducer for F {
type Tag = T;
fn next_tag(&mut self) -> T {
(self)()
}
}
pub trait IntoNotification: __private::Sealed {
type Tag;
type Notify: Notification<Tag = Self::Tag>;
fn into_notification(self) -> Self::Notify;
fn additional(self) -> Additional<Self::Notify>
where
Self: Sized,
{
Additional::new(self.into_notification())
}
fn relaxed(self) -> Relaxed<Self::Notify>
where
Self: Sized,
{
Relaxed::new(self.into_notification())
}
#[cfg(feature = "std")]
fn tag<T: Clone>(self, tag: T) -> Tag<Self::Notify, T>
where
Self: Sized + IntoNotification<Tag = ()>,
{
Tag::new(tag, self.into_notification())
}
#[cfg(feature = "std")]
fn tag_with<T, F>(self, tag: F) -> TagWith<Self::Notify, F>
where
Self: Sized + IntoNotification<Tag = ()>,
F: FnMut() -> T,
{
TagWith::new(tag, self.into_notification())
}
}
impl<N: Notification> IntoNotification for N {
type Tag = N::Tag;
type Notify = N;
fn into_notification(self) -> Self::Notify {
self
}
}
macro_rules! impl_for_numeric_types {
($($ty:ty)*) => {$(
impl IntoNotification for $ty {
type Tag = ();
type Notify = Notify;
#[allow(unused_comparisons)]
fn into_notification(self) -> Self::Notify {
if self < 0 {
panic!("negative notification count");
}
Notify::new(self.try_into().expect("overflow"))
}
}
impl __private::Sealed for $ty {}
)*};
}
impl_for_numeric_types! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
#[inline]
pub(super) fn full_fence() {
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(miri), not(loom)))]
{
use core::{arch::asm, cell::UnsafeCell};
let a = UnsafeCell::new(0_usize);
unsafe {
#[cfg(target_pointer_width = "64")]
asm!("lock not qword ptr [{0}]", in(reg) a.get(), options(nostack, preserves_flags));
#[cfg(target_pointer_width = "32")]
asm!("lock not dword ptr [{0:e}]", in(reg) a.get(), options(nostack, preserves_flags));
}
return;
}
#[allow(unreachable_code)]
{
atomic::fence(Ordering::SeqCst);
}
}
mod __private {
#[doc(hidden)]
#[derive(Debug)]
pub struct Internal(());
impl Internal {
pub(crate) fn new() -> Self {
Self(())
}
}
#[doc(hidden)]
pub trait Sealed {}
impl<N: super::NotificationPrivate + ?Sized> Sealed for N {}
}