use std::ffi::{c_int, c_void};
use std::marker::PhantomPinned;
use std::mem::MaybeUninit;
use std::pin::Pin;
use moveit::{CopyNew, New};
unsafe extern "C" {
fn idakit_cfuncptr_copy_ctor(dst: *mut c_void, src: *const c_void);
fn idakit_cfuncptr_decompile_into(dst: *mut c_void, ea: u64) -> c_int;
fn idakit_cfuncptr_dtor(p: *mut c_void);
fn idakit_cfuncptr_refcnt_raw(p: *const c_void) -> i32;
fn idakit_cfuncptr_is_null_raw(p: *const c_void) -> c_int;
}
#[repr(C)]
pub struct CfuncVal {
ptr: *mut c_void,
_pin: PhantomPinned,
}
impl CfuncVal {
#[must_use]
pub fn refcnt(&self) -> i32 {
unsafe { idakit_cfuncptr_refcnt_raw((self as *const Self).cast()) }
}
#[must_use]
pub fn is_null(&self) -> bool {
unsafe { idakit_cfuncptr_is_null_raw((self as *const Self).cast()) != 0 }
}
}
unsafe impl CopyNew for CfuncVal {
unsafe fn copy_new(src: &Self, this: Pin<&mut MaybeUninit<Self>>) {
unsafe {
let dst = this.get_unchecked_mut().as_mut_ptr();
idakit_cfuncptr_copy_ctor(dst.cast(), (src as *const Self).cast());
}
}
}
impl Drop for CfuncVal {
fn drop(&mut self) {
unsafe { idakit_cfuncptr_dtor((self as *mut Self).cast()) };
}
}
pub struct DecompileVal {
pub ea: u64,
}
unsafe impl New for DecompileVal {
type Output = CfuncVal;
unsafe fn new(self, this: Pin<&mut MaybeUninit<Self::Output>>) {
unsafe {
let dst = this.get_unchecked_mut().as_mut_ptr();
idakit_cfuncptr_decompile_into(dst.cast(), self.ea);
}
}
}
#[must_use]
pub fn cfunc_moveit_inline_probe(ea: u64) -> Option<[i32; 3]> {
moveit::moveit! {
let a = DecompileVal { ea };
}
if a.is_null() {
return None;
}
let after_create = a.refcnt();
let after_clone;
{
moveit::moveit! {
let b = moveit::new::copy(&*a);
}
after_clone = b.refcnt();
}
let after_clone_dropped = a.refcnt();
Some([after_create, after_clone, after_clone_dropped])
}