use crate::{Args, Error, Il2CppValueType, MethodInfo, Result};
use il2cpp_bridge_rs as bridge;
use std::ffi::c_void;
use std::fmt;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Il2CppObject {
pub(crate) inner: bridge::structs::Object,
}
impl Il2CppObject {
pub fn load<T: Il2CppValueType>(&self, name: &str) -> Result<T> {
let field = self
.inner
.field(name)
.ok_or_else(|| Error::FieldNotFound(name.to_string()))?;
unsafe { T::load_field(&field) }
}
pub fn store<T: Il2CppValueType>(&self, name: &str, val: T) -> Result<()> {
let field = self
.inner
.field(name)
.ok_or_else(|| Error::FieldNotFound(name.to_string()))?;
unsafe { T::store_field(&field, val) }
}
pub fn invoke<T: Il2CppValueType>(&self, name: &str) -> Result<T> {
self.invoke_with(name, ())
}
pub fn invoke_void(&self, name: &str) -> Result<()> {
self.invoke_with_void(name, ())
}
pub fn invoke_with<T: Il2CppValueType>(&self, name: &str, args: impl Args) -> Result<T> {
let method = self.method(name)?;
method.invoke(args)
}
pub fn invoke_with_void(&self, name: &str, args: impl Args) -> Result<()> {
let method = self.method(name)?;
method.invoke_void(args)
}
pub fn invoke_raw_void(&self, name: &str, args: &[*mut c_void]) -> Result<()> {
let method = self.method(name)?;
unsafe { method.inner.call::<()>(args).map_err(Error::Bridge) }
}
pub fn method(&self, name: &str) -> Result<MethodInfo> {
let method = self
.inner
.method(name)
.ok_or_else(|| Error::MethodNotFound(name.to_string()))?;
Ok(MethodInfo { inner: method })
}
#[doc(hidden)]
pub fn raw_ptr(&self) -> *mut c_void {
self.inner.ptr as *mut c_void
}
#[doc(hidden)]
pub unsafe fn from_raw(ptr: *mut c_void) -> Self {
Self {
inner: unsafe { bridge::structs::Object::from_ptr(ptr) },
}
}
}
impl fmt::Debug for Il2CppObject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Il2CppObject({:p})", self.inner.as_ptr())
}
}
impl PartialEq for Il2CppObject {
fn eq(&self, other: &Self) -> bool {
self.inner.ptr == other.inner.ptr
}
}
impl Eq for Il2CppObject {}
unsafe impl Send for Il2CppObject {}
unsafe impl Sync for Il2CppObject {}
impl Default for Il2CppObject {
fn default() -> Self {
Self {
inner: unsafe { bridge::structs::Object::from_ptr(std::ptr::null_mut()) },
}
}
}
unsafe impl Il2CppValueType for Il2CppObject {
unsafe fn load_field(field: &il2cpp_bridge_rs::structs::Field) -> Result<Self> {
let ptr = unsafe { field.get_value::<*mut c_void>().map_err(Error::Bridge)? };
let obj = unsafe { bridge::structs::Object::from_ptr(ptr) };
Ok(Il2CppObject { inner: obj })
}
unsafe fn store_field(field: &il2cpp_bridge_rs::structs::Field, val: Self) -> Result<()> {
unsafe {
field
.set_value::<*mut c_void>(val.inner.as_ptr())
.map_err(Error::Bridge)
}
}
}