use lazy_static::lazy_static;
use maybe_uninit::MaybeUninit;
use std::os::raw;
pub trait MapLayout {}
pub unsafe trait ReadPointer<T, L: MapLayout> {
fn get_ptr(self) -> *const raw::c_void;
}
pub unsafe trait WritePointer<T, L: MapLayout> {
fn get_ptr_mut(self) -> *mut raw::c_void;
}
pub struct ScalarLayout;
impl MapLayout for ScalarLayout {}
unsafe impl<T> ReadPointer<T, ScalarLayout> for &T {
fn get_ptr(self) -> *const raw::c_void {
self as *const T as *const raw::c_void
}
}
unsafe impl<T> WritePointer<T, ScalarLayout> for &mut MaybeUninit<T> {
fn get_ptr_mut(self) -> *mut raw::c_void {
self.as_mut_ptr() as *mut raw::c_void
}
}
pub struct PerCpuLayout;
impl MapLayout for PerCpuLayout {}
#[repr(align(8))]
#[derive(Debug)]
pub struct PerCpuValue<T>(T);
lazy_static! {
pub(crate) static ref NB_CPUS: usize = crate::libbpf::libbpf_num_possible_cpus()
.expect("Couldn't get the number of CPUs from BPF")
as usize;
}
impl<T> From<T> for PerCpuValue<T> {
fn from(v: T) -> Self {
PerCpuValue(v)
}
}
impl<T> AsRef<T> for PerCpuValue<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
unsafe impl<T> ReadPointer<T, PerCpuLayout> for &Vec<PerCpuValue<T>> {
fn get_ptr(self) -> *const raw::c_void {
assert!(self.len() == *NB_CPUS, "size mismatch");
self.as_ptr() as *const raw::c_void
}
}
unsafe impl<T> WritePointer<T, PerCpuLayout> for &mut Vec<MaybeUninit<PerCpuValue<T>>> {
fn get_ptr_mut(self) -> *mut raw::c_void {
assert!(self.len() == *NB_CPUS, "size mismatch");
self.as_mut_ptr() as *mut raw::c_void
}
}
#[cfg(test)]
mod test {
use super::*;
use std::mem::{align_of, size_of};
#[test]
fn layout_smaller_content() {
assert_eq!(size_of::<PerCpuValue<u32>>(), 8);
assert_eq!(align_of::<PerCpuValue<u32>>(), 8);
assert_eq!(size_of::<u32>(), 4);
assert_eq!(align_of::<u32>(), 4);
assert_eq!(size_of::<PerCpuValue<u8>>(), 8);
assert_eq!(align_of::<PerCpuValue<u8>>(), 8);
assert_eq!(size_of::<u8>(), 1);
assert_eq!(align_of::<u8>(), 1);
assert_eq!(size_of::<PerCpuValue<(u8, u16)>>(), 8);
assert_eq!(align_of::<PerCpuValue<(u8, u16)>>(), 8);
assert_eq!(size_of::<(u8, u16)>(), 4);
assert_eq!(align_of::<(u8, u16)>(), 2);
}
#[test]
fn layout_bigger_content() {
#[repr(align(16))]
struct U8Align16(u8);
assert_eq!(size_of::<U8Align16>(), 16);
assert_eq!(align_of::<U8Align16>(), 16);
assert_eq!(size_of::<PerCpuValue<U8Align16>>(), 16);
assert_eq!(align_of::<PerCpuValue<U8Align16>>(), 16);
struct U32X3(u32, u32, u32);
assert_eq!(size_of::<U32X3>(), 12);
assert_eq!(align_of::<U32X3>(), 4);
assert_eq!(size_of::<PerCpuValue<U32X3>>(), 16);
assert_eq!(align_of::<PerCpuValue<U32X3>>(), 8);
}
}