use core::fmt;
use core::ops::{Deref, DerefMut};
#[repr(C)]
#[repr(align(64))]
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
struct AlignedInner64<T> {
value: T,
}
#[repr(C)]
#[repr(align(128))]
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
struct AlignedInner128<T> {
value: T,
}
#[cfg(target_arch = "x86_64")]
mod arch_details {
pub const CACHE_LINE_SIZE_USIZE: usize = 64;
pub type ArchAligned<T> = crate::internal::cache_padded::AlignedInner64<T>;
}
#[cfg(target_arch = "aarch64")]
mod arch_details {
pub const CACHE_LINE_SIZE_USIZE: usize = 64;
pub type ArchAligned<T> = crate::internal::cache_padded::AlignedInner64<T>;
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
mod arch_details {
pub const CACHE_LINE_SIZE_USIZE: usize = 64; pub type ArchAligned<T> = crate::internal::cache_padded::AlignedInner64<T>;
}
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
pub(crate) struct CachePadded<T> {
inner: arch_details::ArchAligned<T>,
}
impl<T> CachePadded<T> {
#[inline]
pub(crate) const fn new(value: T) -> Self {
CachePadded {
inner: arch_details::ArchAligned { value },
}
}
#[inline]
pub(crate) const fn alignment_value() -> usize {
arch_details::CACHE_LINE_SIZE_USIZE
}
}
impl<T> Deref for CachePadded<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.inner.value
}
}
impl<T> DerefMut for CachePadded<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.inner.value
}
}
impl<T: fmt::Debug> fmt::Debug for CachePadded<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CachePadded")
.field("value", &self.inner.value)
.field("alignment", &Self::alignment_value())
.finish()
}
}
unsafe impl<T: Send> Send for CachePadded<T> {}
unsafe impl<T: Sync> Sync for CachePadded<T> {}
#[cfg(test)]
mod tests {
use super::*;
use core::mem;
#[test]
fn alignment_check() {
#[derive(Debug)] struct MyData(u64);
let padded_data = CachePadded::new(MyData(0));
let ptr = &padded_data as *const _ as usize;
let expected_alignment = CachePadded::<MyData>::alignment_value();
assert_eq!(
mem::align_of_val(&padded_data),
expected_alignment,
"CachePadded struct alignment mismatch. Expected {}, got {}",
expected_alignment,
mem::align_of_val(&padded_data)
);
assert_eq!(
ptr % expected_alignment,
0,
"CachePadded instance address 0x{:x} is not aligned to {}",
ptr,
expected_alignment
);
let size = mem::size_of_val(&padded_data);
assert!(size >= mem::size_of::<MyData>());
if mem::size_of::<MyData>() <= expected_alignment {
assert_eq!(
size, expected_alignment,
"Size of CachePadded should be the alignment size when T is small enough. Expected {}, got {}",
expected_alignment, size
);
} else {
assert_eq!(
size % expected_alignment,
0,
"Size of CachePadded should be a multiple of alignment when T is large"
);
assert!(size >= mem::size_of::<MyData>());
}
}
#[test]
fn const_constructor() {
static _PADDED_CONST: CachePadded<u32> = CachePadded::new(42);
assert_eq!(*_PADDED_CONST, 42); }
#[test]
fn debug_output() {
let p = CachePadded::new(10i32);
let s = format!("{:?}", p);
assert!(s.contains("CachePadded"));
assert!(s.contains("value: 10"));
assert!(s.contains(&format!("alignment: {}", CachePadded::<i32>::alignment_value())));
}
#[test]
fn deref_mut_works() {
let mut p = CachePadded::new(String::from("hello"));
p.push_str(" world");
assert_eq!(*p, "hello world");
}
}