use core::{
ffi::{CStr, c_char},
marker::PhantomData,
ptr::NonNull,
};
use darwin_kperf_sys::kperfdata::{
KPEP_ARCH_ARM, KPEP_ARCH_ARM64, KPEP_ARCH_I386, KPEP_ARCH_X86_64, kpep_event,
};
use crate::event::Cpu;
const unsafe fn as_str<'db>(field: *const c_char) -> &'db str {
assert!(!field.is_null());
let str = unsafe { CStr::from_ptr(field).to_str() };
match str {
Ok(str) => str,
Err(_) => panic!("string is not utf-8"),
}
}
const unsafe fn as_opt_str<'db>(field: *const c_char) -> Option<&'db str> {
if field.is_null() {
return None;
}
let str = unsafe { CStr::from_ptr(field).to_str() };
match str {
Ok(str) => Some(str),
Err(_) => panic!("string is not utf-8"),
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Architecture {
I386,
X86_64,
Arm,
Arm64,
}
impl Architecture {
const fn from_sys(value: u32) -> Self {
match value {
KPEP_ARCH_I386 => Self::I386,
KPEP_ARCH_X86_64 => Self::X86_64,
KPEP_ARCH_ARM => Self::Arm,
KPEP_ARCH_ARM64 => Self::Arm64,
_ => unreachable!(), }
}
}
pub struct Database<'db> {
inner: &'db darwin_kperf_sys::kperfdata::kpep_db,
}
impl<'db> Database<'db> {
pub(crate) const unsafe fn from_raw(db: &'db darwin_kperf_sys::kperfdata::kpep_db) -> Self {
Self { inner: db }
}
#[must_use]
pub const unsafe fn as_raw(&self) -> NonNull<darwin_kperf_sys::kperfdata::kpep_db> {
NonNull::from_ref(self.inner)
}
#[must_use]
pub const fn name(&self) -> &'db str {
unsafe { as_str(self.inner.name) }
}
#[must_use]
pub const fn cpu_id(&self) -> &'db str {
unsafe { as_str(self.inner.cpu_id) }
}
#[must_use]
pub const fn cpu(&self) -> Option<Cpu> {
Cpu::from_db_name(self.name())
}
#[must_use]
pub const fn marketing_name(&self) -> &'db str {
unsafe { as_str(self.inner.marketing_name) }
}
#[must_use]
pub const fn events(&self) -> &'db [DatabaseEvent<'db>] {
if self.inner.event_arr.is_null() {
return &[];
}
unsafe { core::slice::from_raw_parts(self.inner.event_arr.cast(), self.inner.event_count) }
}
#[must_use]
pub const fn fixed_events(&self) -> &'db [&'db DatabaseEvent<'db>] {
if self.inner.fixed_event_arr.is_null() {
return &[];
}
unsafe {
core::slice::from_raw_parts(
self.inner.fixed_event_arr.cast(),
self.inner.fixed_counter_count,
)
}
}
#[must_use]
pub const fn architecture(&self) -> Architecture {
Architecture::from_sys(self.inner.archtecture)
}
}
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct DatabaseEvent<'db> {
event: kpep_event,
_marker: PhantomData<&'db ()>,
}
impl<'db> DatabaseEvent<'db> {
#[must_use]
pub const fn name(&self) -> &'db str {
unsafe { as_str(self.event.name) }
}
#[must_use]
pub const fn description(&self) -> Option<&'db str> {
unsafe { as_opt_str(self.event.description) }
}
#[must_use]
pub const fn errata(&self) -> Option<&'db str> {
unsafe { as_opt_str(self.event.errata) }
}
#[must_use]
pub const fn alias(&self) -> Option<&'db str> {
unsafe { as_opt_str(self.event.alias) }
}
#[must_use]
pub const fn fallback(&self) -> Option<&'db str> {
unsafe { as_opt_str(self.event.fallback) }
}
#[must_use]
pub const fn is_fixed(&self) -> bool {
self.event.flags & 1 != 0
}
}