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"
|
anyhow = "1.0"
|
||||||
widestring = "1.0"
|
widestring = "1.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
once_cell = "1.17.1"
|
||||||
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
|
@ -1,4 +1,5 @@
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
|
use crate::tarray::{FString, TArray};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
@ -44,8 +45,6 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use tarray::{FString, TArray};
|
|
||||||
|
|
||||||
use crate::global_tables::names::GNAMES;
|
use crate::global_tables::names::GNAMES;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -127,6 +126,95 @@ pub struct UProperty {
|
||||||
post_construct_link_next: Option<NonNull<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)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UFunction {
|
pub struct UFunction {
|
||||||
|
@ -141,110 +229,3 @@ pub struct UFunction {
|
||||||
first_property_to_init: Option<NonNull<UProperty>>,
|
first_property_to_init: Option<NonNull<UProperty>>,
|
||||||
function: Option<NonNull<()>>,
|
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)]
|
#![feature(const_trait_impl, const_ptr_as_ref, const_nonnull_new)]
|
||||||
|
|
||||||
mod core_types;
|
mod core_types;
|
||||||
|
pub mod fname;
|
||||||
pub mod global_tables;
|
pub mod global_tables;
|
||||||
|
pub mod tarray;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod v2_types;
|
pub mod v2_types;
|
||||||
|
|
||||||
pub mod sdk {
|
pub mod sdk {
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet},
|
collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
sync::Mutex,
|
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 itertools::Itertools;
|
||||||
use std::{hash::Hash, ptr::NonNull};
|
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};
|
use self::traits::{AsUObject, AsUStruct, FromRaw};
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ impl Hash for UObject {
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UClass {
|
pub struct UClass {
|
||||||
inner: NonNull<core_types::UClass>,
|
pub(crate) inner: NonNull<core_types::UClass>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for UClass {}
|
impl Eq for UClass {}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! that the contents might very well change under its feet (which they might).
|
//! that the contents might very well change under its feet (which they might).
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use std::{cell::UnsafeCell, ptr::NonNull};
|
use std::{cell::UnsafeCell, marker::PhantomData, ptr::NonNull};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
@ -86,8 +86,8 @@ macro_rules! define_utypes {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct $ty(NonNull<UnsafeCell<()>>);
|
pub struct $ty(NonNull<UnsafeCell<()>>);
|
||||||
|
|
||||||
impl $ty {
|
impl traits::StaticClass for $ty {
|
||||||
pub const fn static_class_name() -> &'static str {
|
fn static_class_name() -> &'static str {
|
||||||
concat!("Class CoreUObject.", $name)
|
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 {
|
macro_rules! impl_asuobject {
|
||||||
($($ty:ty),+) => {
|
($($ty:ty),+) => {
|
||||||
$(
|
$(
|
||||||
impl $ty {
|
impl Eq for $ty {}
|
||||||
pub const fn from_raw(raw: *mut ()) -> Option<Self> {
|
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) {
|
match NonNull::new(raw) {
|
||||||
Some(ptr) => Some(Self(ptr.cast())),
|
Some(ptr) => Some(Self(ptr.cast())),
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn from_nonnull(raw: NonNull<UnsafeCell<()>>) -> Self {
|
fn from_nonnull(raw: NonNull<UnsafeCell<()>>) -> Self {
|
||||||
Self(raw)
|
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 () {
|
const fn raw_mut(&self) -> *mut () {
|
||||||
unsafe { self.0.as_ref().get() as _ }
|
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)]
|
#[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::*;
|
use traits::*;
|
||||||
mod traits {
|
mod traits {
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
use std::ptr::NonNull;
|
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};
|
use super::{EObjectFlags, VTbl};
|
||||||
|
|
||||||
#[const_trait]
|
pub trait StaticClass {
|
||||||
pub trait AsUObject {
|
fn static_class_name() -> &'static str;
|
||||||
fn as_uobject(&self) -> super::UObject;
|
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]
|
#[const_trait]
|
||||||
pub trait UObjectTrait: ~const AsUObject {
|
pub trait UObjectTrait: ~const AsUObject {
|
||||||
|
@ -242,6 +455,12 @@ mod traits {
|
||||||
fn outer(&self) -> &Option<super::UObject> {
|
fn outer(&self) -> &Option<super::UObject> {
|
||||||
unsafe { &*self.as_uobject().raw_ptr().offset(32).cast() }
|
unsafe { &*self.as_uobject().raw_ptr().offset(32).cast() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// utility
|
||||||
|
|
||||||
|
fn is_package_object(&self) -> bool {
|
||||||
|
self.outer().is_none()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[const_trait]
|
#[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]
|
#[const_trait]
|
||||||
pub trait UScriptStructTrait: ~const AsUObject {}
|
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]
|
#[const_trait]
|
||||||
pub trait UClassTrait: ~const AsUObject {}
|
pub trait UClassTrait: ~const UStructTrait {}
|
||||||
|
|
||||||
#[const_trait]
|
#[const_trait]
|
||||||
pub trait UFunctionTrait: ~const AsUObject {
|
pub trait UFunctionTrait: ~const AsUObject {
|
||||||
|
|
Loading…
Reference in a new issue