unreal-sdk/src/types.rs
Janis 724939e5da extracted fname and tarray from raw types into own modules
- tarray and fname are pretty independent from the rest of the type system
2023-04-20 02:36:46 +02:00

653 lines
16 KiB
Rust

use anyhow::Context;
use itertools::Itertools;
use std::{hash::Hash, ptr::NonNull};
use crate::core_types::{self, FName};
use crate::tarray::TArray;
use self::traits::{AsUObject, AsUStruct, FromRaw};
#[repr(transparent)]
#[derive(Debug, Clone)]
pub struct UObject {
inner: NonNull<core_types::UObject>,
}
unsafe impl Send for UObject {}
unsafe impl Sync for UObject {}
impl Eq for UObject {}
impl PartialEq for UObject {
fn eq(&self, other: &Self) -> bool {
unsafe {
self.inner.as_ref().internal_index == other.inner.as_ref().internal_index
&& self.inner.as_ref().name == other.inner.as_ref().name
}
}
}
impl Hash for UObject {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.internal_index().hash(state);
self.name().hash(state);
}
}
#[repr(transparent)]
#[derive(Debug, Clone)]
pub struct UClass {
pub(crate) inner: NonNull<core_types::UClass>,
}
impl Eq for UClass {}
impl PartialEq for UClass {
fn eq(&self, other: &Self) -> bool {
self.as_uobject().eq(&other.as_uobject())
}
}
impl Hash for UClass {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_uobject().hash(state);
}
}
#[repr(transparent)]
#[derive(Debug, Clone)]
pub struct UField {
inner: NonNull<core_types::UField>,
}
impl Eq for UField {}
impl PartialEq for UField {
fn eq(&self, other: &Self) -> bool {
self.as_uobject().eq(&other.as_uobject())
}
}
impl Hash for UField {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_uobject().hash(state);
}
}
impl UObject {
pub fn new(inner: NonNull<core_types::UObject>) -> Self {
Self { inner }
}
pub fn maybe_new(inner: Option<NonNull<core_types::UObject>>) -> Option<Self> {
inner.map(|inner| Self { inner })
}
pub fn to_inner(self) -> NonNull<core_types::UObject> {
self.inner
}
pub const unsafe fn cast<T>(self) -> NonNull<T> {
self.inner.cast::<T>()
}
/// returns a `Self` with the provided raw pointer, if the pointer is not null
pub fn maybe_with_raw(raw: *mut core_types::UObject) -> Option<Self> {
Self::maybe_new(NonNull::new(raw))
}
pub fn class(&self) -> Option<UClass> {
unsafe { self.inner.as_ref().class.map(|inner| UClass::new(inner)) }
}
pub fn internal_index(&self) -> u32 {
unsafe { self.inner.as_ref().internal_index }
}
pub fn name(&self) -> core_types::FName {
unsafe { self.inner.as_ref().name }
}
pub fn get_name(&self) -> anyhow::Result<String> {
let name = self.name();
name.get_name()
.map(|name_str| {
if name.number > 0 {
format!("{}_{}", name_str, name.number)
} else {
name_str
}
})
.map(|name_str| {
name_str
.rfind("/")
.map(|pos| name_str[(pos + 1)..].to_string())
.unwrap_or_else(|| name_str)
})
}
pub fn get_name_or_default(&self) -> String {
self.get_name()
.unwrap_or_else(|_| "DefaultObjectName".to_string())
}
pub fn get_full_name(&self) -> anyhow::Result<String> {
let tmp = self
.iter_outer_objects()
.map(|obj| obj.get_name())
.fold_ok(String::new(), |acc, obj_name| {
format!("{}.{}", obj_name, acc)
})?;
Ok(format!(
"{} {}{}",
self.class()
.context("invalid class pointer")?
.as_uobject()
.get_name_or_default(),
tmp,
self.get_name_or_default()
))
}
pub fn get_full_name_or_default(&self) -> String {
self.get_full_name()
.unwrap_or_else(|_| "DefaultObjectFullName".to_string())
}
pub fn outer(&self) -> Option<UObject> {
unsafe { self.inner.as_ref().outer.map(|inner| UObject::new(inner)) }
}
/// returns the package object of this object
pub fn outermost(&self) -> Option<UObject> {
self.iter_outer_objects().last()
}
pub fn is_package_object(&self) -> bool {
unsafe { self.inner.as_ref().outer.is_none() }
}
pub fn iter_outer_objects(&self) -> OuterObjectIterator {
OuterObjectIterator::new(self.clone())
}
pub fn is_a(&self, other: &UClass) -> bool {
self.class()
.map(|class| class.iter_super_classes().contains(other))
.unwrap_or(false)
}
}
pub struct OuterObjectIterator {
object: UObject,
}
impl OuterObjectIterator {
pub fn new(object: UObject) -> Self {
Self { object }
}
}
impl Iterator for OuterObjectIterator {
type Item = UObject;
fn next(&mut self) -> Option<Self::Item> {
if let Some(outer) = self.object.outer() {
self.object = outer.clone();
Some(outer)
} else {
None
}
}
}
impl From<UObject> for UClass {
fn from(obj: UObject) -> Self {
Self::new(obj.inner.cast())
}
}
impl AsUStruct for UClass {
fn as_ustruct(&self) -> UStruct {
UStruct::new(self.inner.clone().cast())
}
}
impl AsRef<core_types::UClass> for UClass {
fn as_ref(&self) -> &core_types::UClass {
unsafe { self.inner.as_ref() }
}
}
impl FromRaw<core_types::UClass> for UClass {
fn from_non_null(inner: NonNull<core_types::UClass>) -> Self {
Self::new(inner)
}
}
impl UClass {
pub fn new(inner: NonNull<core_types::UClass>) -> Self {
Self { inner }
}
pub fn iter_super_classes(&self) -> SuperClassIter {
SuperClassIter::new(self.clone())
}
}
pub struct SuperClassIter {
class: UClass,
}
impl SuperClassIter {
pub fn new(class: UClass) -> Self {
Self { class }
}
}
impl Iterator for SuperClassIter {
type Item = UClass;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.class.super_struct().map(|spr| spr.as_uobject().into()) {
let item = core::mem::replace(&mut self.class, next);
Some(item)
} else {
None
}
}
}
impl From<UObject> for UField {
fn from(obj: UObject) -> Self {
Self::new(obj.inner.cast())
}
}
impl UField {
pub fn new(inner: NonNull<core_types::UField>) -> Self {
Self { inner }
}
pub fn maybe_new(inner: Option<NonNull<core_types::UField>>) -> Option<Self> {
inner.map(|inner| Self { inner })
}
pub fn maybe_with_raw(raw: *mut core_types::UField) -> Option<Self> {
NonNull::new(raw).map(|inner| Self::new(inner))
}
pub fn as_uobject(&self) -> UObject {
UObject::new(self.inner.clone().cast())
}
pub unsafe fn as_ref(&self) -> &core_types::UField {
self.inner.as_ref()
}
pub fn next(&self) -> Option<Self> {
Self::maybe_new(unsafe { self.as_ref().next })
}
}
#[derive(Debug, Clone)]
pub struct UEnum {
inner: NonNull<core_types::UEnum>,
}
impl From<UObject> for UEnum {
fn from(obj: UObject) -> Self {
Self::new(obj.inner.cast())
}
}
impl UEnum {
pub fn new(inner: NonNull<core_types::UEnum>) -> Self {
Self { inner }
}
pub fn maybe_new(inner: Option<NonNull<core_types::UEnum>>) -> Option<Self> {
inner.map(|inner| Self { inner })
}
pub fn maybe_with_raw(raw: *mut core_types::UEnum) -> Option<Self> {
NonNull::new(raw).map(|inner| Self::new(inner))
}
pub fn as_uobject(&self) -> UObject {
UObject::new(self.inner.clone().cast())
}
pub unsafe fn as_ref(&self) -> &core_types::UEnum {
self.inner.as_ref()
}
pub fn get_names(&self) -> &TArray<FName> {
unsafe { &self.as_ref().names }
}
}
#[derive(Debug, Clone)]
pub struct UStruct {
inner: NonNull<core_types::UStruct>,
}
impl From<UObject> for UStruct {
fn from(obj: UObject) -> Self {
Self::new(obj.inner.cast())
}
}
impl FromRaw<core_types::UStruct> for UStruct {
fn from_non_null(inner: NonNull<core_types::UStruct>) -> Self {
Self::new(inner)
}
}
impl UStruct {
pub fn new(inner: NonNull<core_types::UStruct>) -> Self {
Self { inner }
}
pub unsafe fn as_raw(&self) -> &core_types::UStruct {
self.inner.as_ref()
}
fn super_struct(&self) -> Option<Self> {
Self::from_maybe_non_null(unsafe { self.as_raw().super_field })
}
fn children(&self) -> Option<UField> {
UField::maybe_new(unsafe { self.as_raw().children })
}
fn iter_fields(&self) -> Option<UStructFieldIterator> {
self.children()
.map(|field| UStructFieldIterator::new(field))
}
}
impl traits::AsUStruct for UStruct {
fn as_ustruct(&self) -> UStruct {
self.clone()
}
}
pub struct UStructFieldIterator {
field: UField,
}
impl UStructFieldIterator {
pub fn new(field: UField) -> Self {
Self { field }
}
}
impl Iterator for UStructFieldIterator {
type Item = UField;
fn next(&mut self) -> Option<Self::Item> {
if let Some(mut next) = self.field.next() {
std::mem::swap(&mut self.field, &mut next);
Some(next)
} else {
None
}
}
}
#[derive(Debug, Clone)]
pub struct UScriptStruct {
inner: NonNull<core_types::UStruct>,
}
impl From<UObject> for UScriptStruct {
fn from(obj: UObject) -> Self {
Self::new(obj.inner.cast())
}
}
impl UScriptStruct {
pub fn new(inner: NonNull<core_types::UStruct>) -> Self {
Self { inner }
}
pub fn maybe_new(inner: Option<NonNull<core_types::UStruct>>) -> Option<Self> {
inner.map(|inner| Self { inner })
}
pub fn maybe_with_raw(raw: *mut core_types::UStruct) -> Option<Self> {
NonNull::new(raw).map(|inner| Self::new(inner))
}
pub fn as_uobject(&self) -> UObject {
UObject::new(self.inner.clone().cast())
}
pub unsafe fn as_ref(&self) -> &core_types::UStruct {
self.inner.as_ref()
}
pub fn iter_fields(&self) -> Option<UStructFieldIterator> {
UField::maybe_new(unsafe { self.as_ref().children })
.map(|field| UStructFieldIterator::new(field))
}
}
#[derive(Debug, Clone)]
pub struct UProperty {
inner: NonNull<core_types::UProperty>,
}
impl From<UObject> for UProperty {
/// WARNING: There is no type check on this conversion, so it is most certainly unsafe
fn from(obj: UObject) -> Self {
Self::new(obj.inner.cast())
}
}
impl UProperty {
pub fn new(inner: NonNull<core_types::UProperty>) -> Self {
Self { inner }
}
pub fn maybe_new(inner: Option<NonNull<core_types::UProperty>>) -> Option<Self> {
inner.map(|inner| Self { inner })
}
pub fn maybe_with_raw(raw: *mut core_types::UProperty) -> Option<Self> {
NonNull::new(raw).map(|inner| Self::new(inner))
}
pub fn as_uobject(&self) -> UObject {
UObject::new(self.inner.clone().cast())
}
pub unsafe fn as_ref(&self) -> &core_types::UProperty {
self.inner.as_ref()
}
}
#[derive(Debug, Clone)]
pub struct UFunction {
inner: NonNull<core_types::UFunction>,
}
impl From<UObject> for UFunction {
/// WARNING: There is no type check on this conversion, so it is most certainly unsafe
fn from(obj: UObject) -> Self {
Self::new(obj.inner.cast())
}
}
impl UFunction {
pub fn new(inner: NonNull<core_types::UFunction>) -> Self {
Self { inner }
}
pub fn maybe_new(inner: Option<NonNull<core_types::UFunction>>) -> Option<Self> {
inner.map(|inner| Self { inner })
}
pub fn maybe_with_raw(raw: *mut core_types::UFunction) -> Option<Self> {
NonNull::new(raw).map(|inner| Self::new(inner))
}
pub fn as_uobject(&self) -> UObject {
UObject::new(self.inner.clone().cast())
}
pub unsafe fn as_ref(&self) -> &core_types::UFunction {
self.inner.as_ref()
}
}
#[derive(Debug, Clone)]
pub enum UAnyType {
UObject(UObject),
UClass(UClass),
UField(UField),
UScriptStruct(UScriptStruct),
UProperty(UProperty),
UEnum(UEnum),
UStruct(UStruct),
UFunction(UFunction),
}
impl UAnyType {
pub fn as_uobject(&self) -> UObject {
match self {
UAnyType::UObject(rep) => rep.clone(),
UAnyType::UClass(rep) => rep.as_uobject(),
UAnyType::UField(rep) => rep.as_uobject(),
UAnyType::UScriptStruct(rep) => rep.as_uobject(),
UAnyType::UProperty(rep) => rep.as_uobject(),
UAnyType::UEnum(rep) => rep.as_uobject(),
UAnyType::UStruct(rep) => rep.as_uobject(),
UAnyType::UFunction(rep) => rep.as_uobject(),
}
}
}
impl Hash for UAnyType {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_uobject().hash(state);
}
}
pub mod traits {
use crate::core_types::FName;
use std::ptr::NonNull;
use itertools::Itertools;
use super::{OuterObjectIterator, UClass, UField, UObject, UStruct, UStructFieldIterator};
pub unsafe fn null_ptr_cast<'a, T, U>(ptr: &'a NonNull<T>) -> &'a NonNull<U> {
std::mem::transmute(ptr)
}
pub trait AsUObject: Sized {
fn as_uobject(&self) -> UObject;
fn class(&self) -> Option<UClass> {
self.as_uobject().class()
}
fn internal_index(&self) -> u32 {
self.as_uobject().internal_index()
}
fn name(&self) -> FName {
self.as_uobject().name()
}
fn get_name(&self) -> anyhow::Result<String> {
self.as_uobject().get_name()
}
fn get_name_or_default(&self) -> String {
self.as_uobject().get_name_or_default()
}
fn get_full_name(&self) -> anyhow::Result<String> {
self.as_uobject().get_full_name()
}
fn get_full_name_or_default(&self) -> String {
self.as_uobject().get_full_name_or_default()
}
fn outer(&self) -> Option<UObject> {
self.as_uobject().outer()
}
fn outermost(&self) -> Option<UObject> {
self.as_uobject().outermost()
}
fn is_package_object(&self) -> bool {
self.as_uobject().is_package_object()
}
fn iter_outer_objects(&self) -> OuterObjectIterator {
OuterObjectIterator::new(self.as_uobject())
}
fn is_a(&self, other: &UClass) -> bool {
self.class()
.map(|class| class.iter_super_classes().contains(other))
.unwrap_or(false)
}
}
pub trait AsUStruct {
fn as_ustruct(&self) -> UStruct;
#[inline]
fn children(&self) -> Option<UField> {
self.as_ustruct().children()
}
#[inline]
fn super_struct(&self) -> Option<UStruct> {
self.as_ustruct().super_struct()
}
#[inline]
fn iter_fields(&self) -> Option<UStructFieldIterator> {
self.children()
.map(|field| UStructFieldIterator::new(field))
}
}
impl<T> AsUObject for T
where
T: AsUStruct,
{
fn as_uobject(&self) -> UObject {
UObject::new(self.as_ustruct().inner.cast())
}
}
pub trait FromRaw<R> {
fn from_non_null(inner: NonNull<R>) -> Self;
fn from_raw(raw: *mut R) -> Option<Self>
where
Self: Sized,
{
NonNull::new(raw).map(|inner| Self::from_non_null(inner))
}
fn from_maybe_non_null(inner: Option<NonNull<R>>) -> Option<Self>
where
Self: Sized,
{
inner.map(|inner| Self::from_non_null(inner))
}
}
}