heapless 0.4.1

`static` friendly data structures that don't require dynamic memory allocation
Documentation
use core::sync::atomic::{self, AtomicUsize, Ordering};
#[cfg(feature = "smaller-atomics")]
use core::sync::atomic::{AtomicU16, AtomicU8};

use spsc::{MultiCore, SingleCore};

pub unsafe trait XCore {
    fn is_multi_core() -> bool;
}

unsafe impl XCore for SingleCore {
    fn is_multi_core() -> bool {
        false
    }
}

unsafe impl XCore for MultiCore {
    fn is_multi_core() -> bool {
        true
    }
}

pub unsafe trait Uxx: Into<usize> + Send {
    #[doc(hidden)]
    fn truncate(x: usize) -> Self;

    #[doc(hidden)]
    unsafe fn load_acquire<C>(x: *const Self) -> Self
    where
        C: XCore;

    #[doc(hidden)]
    fn load_relaxed(x: *const Self) -> Self;

    #[doc(hidden)]
    unsafe fn store_release<C>(x: *const Self, val: Self)
    where
        C: XCore;
}

#[cfg(feature = "smaller-atomics")]
unsafe impl Uxx for u8 {
    fn truncate(x: usize) -> Self {
        let max = ::core::u8::MAX;
        if x >= usize::from(max) {
            max
        } else {
            x as u8
        }
    }

    unsafe fn load_acquire<C>(x: *const Self) -> Self
    where
        C: XCore,
    {
        if C::is_multi_core() {
            (*(x as *const AtomicU8)).load(Ordering::Acquire)
        } else {
            let y = (*(x as *const AtomicU8)).load(Ordering::Relaxed);
            atomic::compiler_fence(Ordering::Acquire);
            y
        }
    }

    fn load_relaxed(x: *const Self) -> Self {
        unsafe { (*(x as *const AtomicU8)).load(Ordering::Relaxed) }
    }

    unsafe fn store_release<C>(x: *const Self, val: Self)
    where
        C: XCore,
    {
        if C::is_multi_core() {
            (*(x as *const AtomicU8)).store(val, Ordering::Release)
        } else {
            atomic::compiler_fence(Ordering::Release);
            (*(x as *const AtomicU8)).store(val, Ordering::Relaxed)
        }
    }
}

#[cfg(feature = "smaller-atomics")]
unsafe impl Uxx for u16 {
    fn truncate(x: usize) -> Self {
        let max = ::core::u16::MAX;
        if x >= usize::from(max) {
            max
        } else {
            x as u16
        }
    }

    unsafe fn load_acquire<C>(x: *const Self) -> Self
    where
        C: XCore,
    {
        if C::is_multi_core() {
            (*(x as *const AtomicU16)).load(Ordering::Acquire)
        } else {
            let y = (*(x as *const AtomicU16)).load(Ordering::Relaxed);
            atomic::compiler_fence(Ordering::Acquire);
            y
        }
    }

    fn load_relaxed(x: *const Self) -> Self {
        unsafe { (*(x as *const AtomicU16)).load(Ordering::Relaxed) }
    }

    unsafe fn store_release<C>(x: *const Self, val: Self)
    where
        C: XCore,
    {
        if C::is_multi_core() {
            (*(x as *const AtomicU16)).store(val, Ordering::Release)
        } else {
            atomic::compiler_fence(Ordering::Release);
            (*(x as *const AtomicU16)).store(val, Ordering::Relaxed)
        }
    }
}

unsafe impl Uxx for usize {
    fn truncate(x: usize) -> Self {
        x
    }

    unsafe fn load_acquire<C>(x: *const Self) -> Self
    where
        C: XCore,
    {
        if C::is_multi_core() {
            (*(x as *const AtomicUsize)).load(Ordering::Acquire)
        } else {
            let y = (*(x as *const AtomicUsize)).load(Ordering::Relaxed);
            atomic::compiler_fence(Ordering::Acquire);
            y
        }
    }

    fn load_relaxed(x: *const Self) -> Self {
        unsafe { (*(x as *const AtomicUsize)).load(Ordering::Relaxed) }
    }

    unsafe fn store_release<C>(x: *const Self, val: Self)
    where
        C: XCore,
    {
        if C::is_multi_core() {
            (*(x as *const AtomicUsize)).store(val, Ordering::Release)
        } else {
            atomic::compiler_fence(Ordering::Release);
            (*(x as *const AtomicUsize)).store(val, Ordering::Relaxed);
        }
    }
}