rusteal-core 0.8.0

Safe Rust runtime for rusteal (object refs, lifecycle, dynamic calls)
Documentation
use std::marker::PhantomData;

use rusteal_ffi::UObjectHandle;

use crate::dynamic_call::DynamicCall;
use crate::error::{RustealError, RustealResult};
use crate::ffi_dispatch;
use crate::object_ref::UObjectRef;
use crate::traits::{UeClass, UeInterface};

#[repr(transparent)]
pub struct ScriptInterface<I: UeInterface + ?Sized> {
    handle: UObjectHandle,
    _marker: PhantomData<*const I>,
}

impl<I: UeInterface + ?Sized> Clone for ScriptInterface<I> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<I: UeInterface + ?Sized> Copy for ScriptInterface<I> {}

impl<I: UeInterface + ?Sized> PartialEq for ScriptInterface<I> {
    fn eq(&self, other: &Self) -> bool {
        self.handle == other.handle
    }
}

impl<I: UeInterface + ?Sized> Eq for ScriptInterface<I> {}

impl<I: UeInterface + ?Sized> std::fmt::Debug for ScriptInterface<I> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ScriptInterface")
            .field("handle", &self.handle)
            .finish()
    }
}

unsafe impl<I: UeInterface + ?Sized> Send for ScriptInterface<I> {}

impl<I: UeInterface + ?Sized> ScriptInterface<I> {
    #[track_caller]
    pub fn new(object: UObjectHandle) -> RustealResult<Self> {
        if !unsafe { ffi_dispatch::core_is_valid(object) } {
            return Err(RustealError::object_destroyed());
        }

        if !unsafe { ffi_dispatch::core_is_a(object, I::static_class()) } {
            return Err(RustealError::invalid_cast_to(object, I::static_class()));
        }

        Ok(ScriptInterface {
            handle: object,
            _marker: PhantomData,
        })
    }

    #[inline]
    pub fn raw(&self) -> UObjectHandle {
        self.handle
    }

    #[inline]
    pub fn is_valid(&self) -> bool {
        unsafe { ffi_dispatch::core_is_valid(self.handle) }
    }

    #[track_caller]
    pub fn object<T: UeClass>(&self) -> RustealResult<UObjectRef<T>> {
        unsafe { UObjectRef::<T>::from_raw(self.handle) }.cast()
    }

    #[track_caller]
    pub fn call(&self, function: &str) -> RustealResult<DynamicCall> {
        if !self.is_valid() {
            return Err(RustealError::object_destroyed());
        }

        DynamicCall::on_object(self.handle, function)
    }
}