use std::marker::PhantomData;
use idakit_sys as sys;
use crate::Database;
use crate::error::{Error, Result};
use crate::ffi::{nul_checked, reason_or};
use crate::types::TypeWriteError;
impl Database {
#[must_use]
#[doc(alias("BTF_VOID"))]
pub fn type_void(&self) -> TypeInfo {
crate::claim::ensure_kernel_thread();
TypeInfo::from_handle(sys::tinfo_void())
}
#[must_use]
#[doc(alias("BTF_BOOL"))]
pub fn type_bool(&self) -> TypeInfo {
crate::claim::ensure_kernel_thread();
TypeInfo::from_handle(sys::tinfo_bool())
}
#[doc(alias("BTF_INT"))]
pub fn type_int(&self, bytes: u32, signed: bool) -> Result<TypeInfo> {
crate::claim::ensure_kernel_thread();
TypeInfo::from_nullable(sys::tinfo_int(bytes, signed)).ok_or_else(|| {
TypeWriteError::BuildFailed {
reason: format!("{bytes} is not a valid integer width (1, 2, 4, 8, or 16)"),
}
.into()
})
}
#[doc(alias("BTF_FLOAT"))]
pub fn type_float(&self, bytes: u32) -> Result<TypeInfo> {
crate::claim::ensure_kernel_thread();
TypeInfo::from_nullable(sys::tinfo_float(bytes)).ok_or_else(|| {
TypeWriteError::BuildFailed {
reason: format!("{bytes} is not a valid float width (4 or 8)"),
}
.into()
})
}
#[doc(alias("get_named_type"))]
pub fn type_ref(&self, name: impl AsRef<str>) -> Result<TypeInfo> {
let name = nul_checked(name.as_ref(), "name")?;
match self.type_named(name) {
Ok(_) => Ok(TypeInfo::from_handle(sys::tinfo_named(name))),
Err(Error::TypeNotFound { .. }) => Err(TypeWriteError::NoType {
name: name.to_owned(),
}
.into()),
Err(e) => Err(e),
}
}
#[doc(alias("parse_decl"))]
pub fn parse_type(&self, decl: impl AsRef<str>) -> Result<TypeInfo> {
let decl = nul_checked(decl.as_ref(), "decl")?;
crate::claim::ensure_kernel_thread();
match sys::tinfo_decl(decl) {
Ok(handle) => Ok(TypeInfo::from_handle(handle)),
Err(e) => Err(TypeWriteError::ParseFailed {
decl: decl.to_owned(),
reason: reason_or(e.what(), "the declaration is not valid"),
}
.into()),
}
}
}
#[doc(alias("tinfo_t"))]
pub struct TypeInfo {
handle: cxx::UniquePtr<sys::TInfo>,
_not_send: PhantomData<*const ()>,
}
impl TypeInfo {
#[inline]
fn from_handle(handle: cxx::UniquePtr<sys::TInfo>) -> Self {
debug_assert!(!handle.is_null());
Self {
handle,
_not_send: PhantomData,
}
}
#[inline]
fn from_nullable(handle: cxx::UniquePtr<sys::TInfo>) -> Option<Self> {
(!handle.is_null()).then_some(Self {
handle,
_not_send: PhantomData,
})
}
#[inline]
pub(crate) fn tinfo(&self) -> &sys::TInfo {
self.handle.as_ref().expect("live handle")
}
#[doc(alias("BT_PTR"))]
pub fn pointer(&self) -> Result<Self> {
Self::from_nullable(sys::tinfo_ptr(self.tinfo())).ok_or_else(|| {
TypeWriteError::BuildFailed {
reason: "could not build a pointer to the type".to_owned(),
}
.into()
})
}
#[doc(alias("BT_ARRAY"))]
pub fn array(&self, nelems: u32) -> Result<Self> {
Self::from_nullable(sys::tinfo_array(self.tinfo(), u64::from(nelems))).ok_or_else(|| {
TypeWriteError::BuildFailed {
reason: format!("could not build a {nelems}-element array of the type"),
}
.into()
})
}
#[must_use]
#[doc(alias("BTM_CONST"))]
pub fn const_(&self) -> Self {
Self::from_handle(sys::tinfo_const(self.tinfo()))
}
#[must_use]
#[doc(alias("BTM_VOLATILE"))]
pub fn volatile_(&self) -> Self {
Self::from_handle(sys::tinfo_volatile(self.tinfo()))
}
}
impl std::fmt::Debug for TypeInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TypeInfo").finish_non_exhaustive()
}
}