#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(clippy::undocumented_unsafe_blocks)]
#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
mod boxed;
mod exceptions;
mod lock;
#[cfg(feature = "derive")]
pub mod derive;
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
pub use self::exceptions::exception_free;
pub use self::{exceptions::ExceptionFree, lock::ExceptionLock};
use core::marker::PhantomData;
pub unsafe trait Cores {
fn core_index() -> usize;
}
#[derive(Default)]
#[cfg_attr(
feature = "zerocopy",
derive(
zerocopy::FromBytes,
zerocopy::Immutable,
zerocopy::KnownLayout,
zerocopy::Unaligned
)
)]
#[repr(transparent)]
pub struct PerCore<V: ?Sized, C: Cores> {
_cores: PhantomData<C>,
values: V,
}
impl<V, C: Cores> PerCore<V, C> {
pub const fn new(values: V) -> Self {
Self {
values,
_cores: PhantomData,
}
}
pub fn into_inner(self) -> V {
self.values
}
}
impl<T, C: Cores, const CORE_COUNT: usize> PerCore<[T; CORE_COUNT], C> {
pub fn get(&self) -> &T {
&self.values[C::core_index()]
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.values[C::core_index()]
}
}
unsafe impl<T: Send, C: Cores, const CORE_COUNT: usize> Sync
for PerCore<[ExceptionLock<T>; CORE_COUNT], C>
{
}
#[cfg(test)]
mod tests {
use super::*;
use core::cell::RefCell;
pub struct FakeCoresImpl;
unsafe impl Cores for FakeCoresImpl {
fn core_index() -> usize {
0
}
}
#[test]
fn percore_state() {
static STATE: PerCore<[ExceptionLock<RefCell<u32>>; 4], FakeCoresImpl> =
PerCore::new([const { ExceptionLock::new(RefCell::new(42)) }; 4]);
{
let token = unsafe { ExceptionFree::new() };
assert_eq!(*STATE.get().borrow_mut(token), 42);
*STATE.get().borrow_mut(token) += 1;
assert_eq!(*STATE.get().borrow_mut(token), 43);
}
}
#[test]
fn exception_lock_into_inner() {
let lock = ExceptionLock::new(42u32);
assert_eq!(lock.into_inner(), 42);
let lock = ExceptionLock::new(RefCell::new(100u32));
let inner = lock.into_inner();
assert_eq!(inner.into_inner(), 100);
}
}