extracted fname and tarray from raw types into own modules
- tarray and fname are pretty independent from the rest of the type system
This commit is contained in:
parent
e68aa9ec55
commit
724939e5da
|
@ -14,6 +14,7 @@ bitflags = "1.0.0"
|
|||
anyhow = "1.0"
|
||||
widestring = "1.0"
|
||||
lazy_static = "1.4.0"
|
||||
once_cell = "1.17.1"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
|
@ -1,4 +1,5 @@
|
|||
#![allow(non_upper_case_globals)]
|
||||
use crate::tarray::{FString, TArray};
|
||||
use bitflags::bitflags;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
|
@ -44,8 +45,6 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
pub use tarray::{FString, TArray};
|
||||
|
||||
use crate::global_tables::names::GNAMES;
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -127,6 +126,95 @@ pub struct UProperty {
|
|||
post_construct_link_next: Option<NonNull<UProperty>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UByteProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
uenum: Option<NonNull<UEnum>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UBoolProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
field_size: u8,
|
||||
byte_offset: u8,
|
||||
byte_mask: u8,
|
||||
field_mask: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UObjectProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
property_class: Option<NonNull<UClass>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UClassProperty {
|
||||
pub(crate) uobjectproperty: UObjectProperty,
|
||||
meta_class: Option<NonNull<UClass>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UAssetClassProperty {
|
||||
pub(crate) uobjectproperty: UObjectProperty,
|
||||
meta_class: Option<NonNull<UClass>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UInterfaceProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
interface_class: Option<NonNull<UClass>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UStructProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
ustruct: Option<NonNull<UStruct>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UArrayProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
inner: Option<NonNull<UProperty>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UMapProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
key_prop: Option<NonNull<UProperty>>,
|
||||
value_prop: Option<NonNull<UProperty>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UDelegateProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
signature_function: Option<NonNull<UFunction>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UMulticastDelegateProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
signature_function: Option<NonNull<UFunction>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UEnumProperty {
|
||||
pub(crate) uproperty: UProperty,
|
||||
underlying_type: Option<NonNull<UProperty>>,
|
||||
uenum: Option<NonNull<UEnum>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct UFunction {
|
||||
|
@ -141,110 +229,3 @@ pub struct UFunction {
|
|||
first_property_to_init: Option<NonNull<UProperty>>,
|
||||
function: Option<NonNull<()>>,
|
||||
}
|
||||
|
||||
pub mod tarray {
|
||||
use std::{ops::Index, ptr::NonNull, slice::SliceIndex};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct TArray<T> {
|
||||
data: Option<NonNull<T>>,
|
||||
count: u32,
|
||||
max: u32,
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for TArray<T> where T: Send {}
|
||||
unsafe impl<T> Sync for TArray<T> where T: Sync {}
|
||||
|
||||
pub type FString = TArray<u16>;
|
||||
|
||||
impl ToString for FString {
|
||||
fn to_string(&self) -> String {
|
||||
widestring::U16CStr::from_slice(&self)
|
||||
.expect("invalid utf16 string")
|
||||
.to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TArray<T> {
|
||||
pub fn len(&self) -> usize {
|
||||
self.count as usize
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.max as usize
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
match self.data {
|
||||
Some(ptr) => unsafe { core::slice::from_raw_parts(ptr.as_ptr(), self.len()) },
|
||||
None => unsafe { core::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice_mut(&mut self) -> &mut [T] {
|
||||
match self.data {
|
||||
Some(ptr) => unsafe { core::slice::from_raw_parts_mut(ptr.as_ptr(), self.len()) },
|
||||
None => unsafe { core::slice::from_raw_parts_mut(NonNull::dangling().as_ptr(), 0) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: SliceIndex<[T]>> Index<I> for TArray<T> {
|
||||
type Output = I::Output;
|
||||
|
||||
fn index(&self, i: I) -> &Self::Output {
|
||||
let data = self.as_slice();
|
||||
|
||||
&data[i]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for TArray<T> {
|
||||
type Target = [T];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntoIter<T> {
|
||||
//array_ref: &'a TArray<T>,
|
||||
ptr: *const T,
|
||||
end: *const T,
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIter<T> {
|
||||
pub fn new(array: &'a TArray<T>) -> Self {
|
||||
let ptr = array.data.unwrap().as_ptr();
|
||||
Self {
|
||||
ptr,
|
||||
end: unsafe { ptr.offset(array.count as isize) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if self.ptr == self.end {
|
||||
None
|
||||
} else {
|
||||
let old = self.ptr;
|
||||
self.ptr = unsafe { self.ptr.offset(1) };
|
||||
|
||||
Some(unsafe { std::ptr::read(old) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a TArray<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
19
src/fname.rs
Normal file
19
src/fname.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use crate::global_tables::names::GNAMES;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
|
||||
pub struct FName {
|
||||
pub comparison_index: u32,
|
||||
pub number: u32,
|
||||
}
|
||||
|
||||
impl FName {
|
||||
pub fn get_name(&self) -> anyhow::Result<String> {
|
||||
GNAMES
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_names()
|
||||
.unwrap()
|
||||
.fname_to_string(self)
|
||||
}
|
||||
}
|
|
@ -1,14 +1,16 @@
|
|||
#![feature(const_trait_impl, const_ptr_as_ref, const_nonnull_new)]
|
||||
|
||||
mod core_types;
|
||||
pub mod fname;
|
||||
pub mod global_tables;
|
||||
pub mod tarray;
|
||||
pub mod types;
|
||||
pub mod v2_types;
|
||||
|
||||
pub mod sdk {
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet},
|
||||
collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
|
||||
fmt::Display,
|
||||
sync::Mutex,
|
||||
};
|
||||
|
|
104
src/tarray.rs
Normal file
104
src/tarray.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
use std::{ops::Index, ptr::NonNull, slice::SliceIndex};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct TArray<T> {
|
||||
data: Option<NonNull<T>>,
|
||||
count: u32,
|
||||
max: u32,
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for TArray<T> where T: Send {}
|
||||
unsafe impl<T> Sync for TArray<T> where T: Sync {}
|
||||
|
||||
pub type FString = TArray<u16>;
|
||||
|
||||
impl ToString for FString {
|
||||
fn to_string(&self) -> String {
|
||||
widestring::U16CStr::from_slice(&self)
|
||||
.expect("invalid utf16 string")
|
||||
.to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TArray<T> {
|
||||
pub fn len(&self) -> usize {
|
||||
self.count as usize
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.max as usize
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
match self.data {
|
||||
Some(ptr) => unsafe { core::slice::from_raw_parts(ptr.as_ptr(), self.len()) },
|
||||
None => unsafe { core::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice_mut(&mut self) -> &mut [T] {
|
||||
match self.data {
|
||||
Some(ptr) => unsafe { core::slice::from_raw_parts_mut(ptr.as_ptr(), self.len()) },
|
||||
None => unsafe { core::slice::from_raw_parts_mut(NonNull::dangling().as_ptr(), 0) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: SliceIndex<[T]>> Index<I> for TArray<T> {
|
||||
type Output = I::Output;
|
||||
|
||||
fn index(&self, i: I) -> &Self::Output {
|
||||
let data = self.as_slice();
|
||||
|
||||
&data[i]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for TArray<T> {
|
||||
type Target = [T];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntoIter<T> {
|
||||
//array_ref: &'a TArray<T>,
|
||||
ptr: *const T,
|
||||
end: *const T,
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIter<T> {
|
||||
pub fn new(array: &'a TArray<T>) -> Self {
|
||||
let ptr = array.data.unwrap().as_ptr();
|
||||
Self {
|
||||
ptr,
|
||||
end: unsafe { ptr.offset(array.count as isize) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if self.ptr == self.end {
|
||||
None
|
||||
} else {
|
||||
let old = self.ptr;
|
||||
self.ptr = unsafe { self.ptr.offset(1) };
|
||||
|
||||
Some(unsafe { std::ptr::read(old) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a TArray<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
|
@ -2,7 +2,8 @@ use anyhow::Context;
|
|||
use itertools::Itertools;
|
||||
use std::{hash::Hash, ptr::NonNull};
|
||||
|
||||
use crate::core_types::{self, FName, TArray};
|
||||
use crate::core_types::{self, FName};
|
||||
use crate::tarray::TArray;
|
||||
|
||||
use self::traits::{AsUObject, AsUStruct, FromRaw};
|
||||
|
||||
|
@ -36,7 +37,7 @@ impl Hash for UObject {
|
|||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UClass {
|
||||
inner: NonNull<core_types::UClass>,
|
||||
pub(crate) inner: NonNull<core_types::UClass>,
|
||||
}
|
||||
|
||||
impl Eq for UClass {}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! that the contents might very well change under its feet (which they might).
|
||||
#![allow(non_upper_case_globals)]
|
||||
use bitflags::bitflags;
|
||||
use std::{cell::UnsafeCell, ptr::NonNull};
|
||||
use std::{cell::UnsafeCell, marker::PhantomData, ptr::NonNull};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
|
@ -86,8 +86,8 @@ macro_rules! define_utypes {
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct $ty(NonNull<UnsafeCell<()>>);
|
||||
|
||||
impl $ty {
|
||||
pub const fn static_class_name() -> &'static str {
|
||||
impl traits::StaticClass for $ty {
|
||||
fn static_class_name() -> &'static str {
|
||||
concat!("Class CoreUObject.", $name)
|
||||
}
|
||||
}
|
||||
|
@ -102,36 +102,35 @@ macro_rules! define_utypes {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_const_trait_for {
|
||||
|
||||
($trt:ty: $($ty:ty),+) => {
|
||||
$(
|
||||
impl const $trt for $ty {}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_asuobject {
|
||||
($($ty:ty),+) => {
|
||||
$(
|
||||
impl $ty {
|
||||
pub const fn from_raw(raw: *mut ()) -> Option<Self> {
|
||||
impl Eq for $ty {}
|
||||
impl<T> PartialEq<T> for $ty where T: AsUObject{
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
self.as_uobject().partial_eq(&other.as_uobject())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for $ty {}
|
||||
unsafe impl Sync for $ty {}
|
||||
|
||||
impl const traits::AsUObject for $ty {
|
||||
fn as_uobject(&self) -> self::UObject {
|
||||
self::UObject(self.0)
|
||||
}
|
||||
|
||||
fn from_raw(raw: *mut ()) -> Option<Self> {
|
||||
match NonNull::new(raw) {
|
||||
Some(ptr) => Some(Self(ptr.cast())),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn from_nonnull(raw: NonNull<UnsafeCell<()>>) -> Self {
|
||||
fn from_nonnull(raw: NonNull<UnsafeCell<()>>) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl const traits::AsUObject for $ty {
|
||||
fn as_uobject(&self) -> self::UObject {
|
||||
self::UObject(self.0)
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
@ -189,6 +188,10 @@ impl UObject {
|
|||
const fn raw_mut(&self) -> *mut () {
|
||||
unsafe { self.0.as_ref().get() as _ }
|
||||
}
|
||||
|
||||
fn partial_eq(&self, other: &Self) -> bool {
|
||||
self.internal_index() == other.internal_index() && self.name() == other.name()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
|
@ -209,18 +212,228 @@ impl UEnum {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct OuterObjectIter<'a> {
|
||||
object: UObject,
|
||||
phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> OuterObjectIter<'a> {
|
||||
pub fn new(object: UObject) -> Self {
|
||||
Self {
|
||||
object,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for OuterObjectIter<'a> {
|
||||
type Item = UObject;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(outer) = self.object.outer() {
|
||||
self.object = *outer;
|
||||
|
||||
Some(self.object)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SuperStructIter<'a> {
|
||||
class: Option<UStruct>,
|
||||
phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> SuperStructIter<'a> {
|
||||
pub fn new(class: UStruct) -> Self {
|
||||
Self {
|
||||
class: Some(class),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn from_option(class: Option<UStruct>) -> Self {
|
||||
Self {
|
||||
class,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SuperStructIter<'a> {
|
||||
type Item = UStruct;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let next = *self.class?.super_field();
|
||||
|
||||
core::mem::replace(&mut self.class, next)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SuperClassIter<'a>(SuperStructIter<'a>);
|
||||
|
||||
impl<'a> SuperClassIter<'a> {
|
||||
pub fn new(class: UClass) -> Self {
|
||||
Self(SuperStructIter::new(unsafe { class.cast() }))
|
||||
}
|
||||
|
||||
pub fn from_option(class: Option<UClass>) -> Self {
|
||||
Self(SuperStructIter::from_option(
|
||||
class.map(|c| unsafe { c.cast() }),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SuperClassIter<'a> {
|
||||
type Item = UClass;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next().map(|class| unsafe { class.cast() })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChildIter<'a> {
|
||||
children: Option<UField>,
|
||||
phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> ChildIter<'a> {
|
||||
pub fn new(children: Option<UField>) -> Self {
|
||||
Self {
|
||||
children,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ChildIter<'a> {
|
||||
type Item = UField;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let next = *self.children?.next();
|
||||
|
||||
core::mem::replace(&mut self.children, next)
|
||||
}
|
||||
}
|
||||
|
||||
use traits::*;
|
||||
mod traits {
|
||||
use std::cell::UnsafeCell;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use crate::core_types::{FName, FString, TArray};
|
||||
use anyhow::Context;
|
||||
use itertools::Itertools;
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::fname::FName;
|
||||
use crate::global_tables::objects::{FindClass, GOBJECTS};
|
||||
use crate::tarray::{FString, TArray};
|
||||
|
||||
use super::{EObjectFlags, VTbl};
|
||||
|
||||
#[const_trait]
|
||||
pub trait AsUObject {
|
||||
fn as_uobject(&self) -> super::UObject;
|
||||
pub trait StaticClass {
|
||||
fn static_class_name() -> &'static str;
|
||||
fn static_class() -> super::UClass {
|
||||
// this is something that we always do in C/C++ but unfortinately requires a blanket impl Sync + Send on all UObject types..
|
||||
static CLASS: OnceCell<super::UClass> = OnceCell::new();
|
||||
|
||||
*CLASS.get_or_init(|| {
|
||||
super::UClass(
|
||||
GOBJECTS
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_objects()
|
||||
.unwrap()
|
||||
.find_class(Self::static_class_name())
|
||||
.expect("static class not found!")
|
||||
.inner
|
||||
.cast(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[const_trait]
|
||||
pub trait AsUObject: Sized {
|
||||
fn as_uobject(&self) -> super::UObject;
|
||||
|
||||
fn from_raw(raw: *mut ()) -> Option<Self>;
|
||||
|
||||
fn from_nonnull(raw: NonNull<UnsafeCell<()>>) -> Self;
|
||||
|
||||
unsafe fn cast<T>(&self) -> T
|
||||
where
|
||||
T: ~const AsUObject,
|
||||
{
|
||||
T::from_nonnull(self.as_uobject().0)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UObjectNonConst: UObjectTrait {
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
fn get_name_or_default(&self) -> String {
|
||||
self.get_name()
|
||||
.unwrap_or_else(|_| "DefaultObjectName".to_string())
|
||||
}
|
||||
|
||||
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")?
|
||||
.get_name_or_default(),
|
||||
tmp,
|
||||
self.get_name_or_default()
|
||||
))
|
||||
}
|
||||
|
||||
fn get_full_name_or_default(&self) -> String {
|
||||
self.get_full_name()
|
||||
.unwrap_or_else(|_| "DefaultObjectFullName".to_string())
|
||||
}
|
||||
|
||||
fn iter_outer_objects(&self) -> super::OuterObjectIter {
|
||||
super::OuterObjectIter::new(self.as_uobject())
|
||||
}
|
||||
|
||||
fn package_object(&self) -> super::UObject {
|
||||
self.iter_outer_objects()
|
||||
.last()
|
||||
.unwrap_or(self.as_uobject())
|
||||
}
|
||||
|
||||
fn is_a(&self, other: &super::UClass) -> bool {
|
||||
self.class()
|
||||
.map(|class| class.iter_super_classes().contains(other))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UObjectNonConst for T where T: UObjectTrait {}
|
||||
|
||||
#[const_trait]
|
||||
pub trait UObjectTrait: ~const AsUObject {
|
||||
|
@ -242,6 +455,12 @@ mod traits {
|
|||
fn outer(&self) -> &Option<super::UObject> {
|
||||
unsafe { &*self.as_uobject().raw_ptr().offset(32).cast() }
|
||||
}
|
||||
|
||||
// utility
|
||||
|
||||
fn is_package_object(&self) -> bool {
|
||||
self.outer().is_none()
|
||||
}
|
||||
}
|
||||
|
||||
#[const_trait]
|
||||
|
@ -280,11 +499,31 @@ mod traits {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait UStructNonConst: UStructTrait {
|
||||
fn iter_super_structs(&self) -> super::SuperStructIter {
|
||||
super::SuperStructIter::from_option(*self.super_field())
|
||||
}
|
||||
|
||||
fn iter_children(&self) -> super::ChildIter {
|
||||
super::ChildIter::new(*self.children())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UStructNonConst for T where T: UStructTrait {}
|
||||
|
||||
#[const_trait]
|
||||
pub trait UScriptStructTrait: ~const AsUObject {}
|
||||
|
||||
pub trait UClassNonConst: UClassTrait {
|
||||
fn iter_super_classes(&self) -> super::SuperClassIter {
|
||||
super::SuperClassIter::from_option(self.super_field().map(|c| unsafe { c.cast() }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UClassNonConst for T where T: UClassTrait {}
|
||||
|
||||
#[const_trait]
|
||||
pub trait UClassTrait: ~const AsUObject {}
|
||||
pub trait UClassTrait: ~const UStructTrait {}
|
||||
|
||||
#[const_trait]
|
||||
pub trait UFunctionTrait: ~const AsUObject {
|
||||
|
|
Loading…
Reference in a new issue