Skip to content

Commit dba9e8f

Browse files
committed
Rework trait system (again) BUT generics (yay)
1 parent e2682af commit dba9e8f

File tree

11 files changed

+154
-198
lines changed

11 files changed

+154
-198
lines changed

libil2cpp/src/array.rs

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,43 @@ use std::mem::transmute;
33
use std::ops::{Deref, DerefMut};
44
use std::{fmt, ptr, slice};
55

6-
use crate::{raw, Il2CppObject, Type, WrapRaw};
6+
use crate::{raw, Il2CppClass, Il2CppObject, Type, WrapRaw};
77

88
/// An il2cpp array
99
#[repr(transparent)]
10-
pub struct Il2CppArray<T>(raw::Il2CppArray, PhantomData<[T]>);
10+
pub struct Il2CppArray<T: Type>(raw::Il2CppArray, PhantomData<[T]>);
1111

12-
impl<T> Il2CppArray<T> {
12+
impl<T: Type> Il2CppArray<T> {
1313
/// Creates an array from a slice
14-
pub fn from_slice(slice: &[T]) -> &Self
14+
pub fn from_slice<'a>(slice: &'a [T::Held<'a>]) -> &'a Self
1515
where
16-
T: Clone + Type,
16+
T::Held<'a>: Clone,
1717
{
1818
let len = slice.len();
19-
let arr = unsafe { raw::array_new(T::class().raw(), len) };
20-
let data_ptr = ((arr as isize) + (raw::kIl2CppSizeOfArray as isize)) as *mut T;
19+
let arr = unsafe { raw::array_new(T::class().raw(), len) }.unwrap();
20+
let data_ptr =
21+
((arr as *mut _ as isize) + (raw::kIl2CppSizeOfArray as isize)) as *mut T::Held<'a>;
2122
for (i, elem) in slice.iter().enumerate() {
2223
unsafe {
2324
let ptr = data_ptr.add(i);
2425
ptr::write_unaligned(ptr, elem.clone());
2526
}
2627
}
27-
unsafe { Self::wrap_ptr_mut(arr) }.unwrap()
28+
unsafe { Self::wrap_mut(arr) }
2829
}
2930

3031
/// Slice of values in the array
31-
pub fn as_slice(&self) -> &[T] {
32-
let ptr = ((self as *const _ as isize) + (raw::kIl2CppSizeOfArray as isize)) as *const T;
32+
pub fn as_slice(&self) -> &[T::Held<'_>] {
33+
let ptr = ((self as *const _ as isize) + (raw::kIl2CppSizeOfArray as isize))
34+
as *const T::Held<'_>;
3335
let len = self.len();
3436
unsafe { slice::from_raw_parts(ptr, len) }
3537
}
3638

3739
/// Mutable slice of values in the array
38-
pub fn as_mut_slice(&mut self) -> &mut [T] {
39-
let ptr = ((self as *mut _ as isize) + (raw::kIl2CppSizeOfArray as isize)) as *mut T;
40+
pub fn as_mut_slice(&mut self) -> &mut [T::Held<'_>] {
41+
let ptr =
42+
((self as *mut _ as isize) + (raw::kIl2CppSizeOfArray as isize)) as *mut T::Held<'_>;
4043
let len = self.len();
4144
unsafe { slice::from_raw_parts_mut(ptr, len) }
4245
}
@@ -57,38 +60,59 @@ impl<T> Il2CppArray<T> {
5760
}
5861
}
5962

60-
unsafe impl<T> WrapRaw for Il2CppArray<T> {
63+
unsafe impl<T: Type> WrapRaw for Il2CppArray<T> {
6164
type Raw = raw::Il2CppArray;
6265
}
6366

64-
impl<T: fmt::Debug> fmt::Debug for Il2CppArray<T> {
67+
unsafe impl<T: Type> Type for Il2CppArray<T> {
68+
type Held<'a> = Option<&'a mut Self>;
69+
70+
const NAMESPACE: &'static str = "System";
71+
const CLASS_NAME: &'static str = "Array";
72+
73+
fn class() -> &'static Il2CppClass {
74+
let class = unsafe { raw::array_class_get(T::class().raw(), 0, false) };
75+
unsafe { Il2CppClass::wrap(class) }
76+
}
77+
78+
fn matches_reference_argument(ty: &crate::Il2CppType) -> bool {
79+
ty.class().is_assignable_from(Self::class())
80+
}
81+
82+
fn matches_value_argument(_: &crate::Il2CppType) -> bool {
83+
false
84+
}
85+
86+
fn matches_reference_parameter(ty: &crate::Il2CppType) -> bool {
87+
Self::class().is_assignable_from(ty.class())
88+
}
89+
90+
fn matches_value_parameter(_: &crate::Il2CppType) -> bool {
91+
false
92+
}
93+
}
94+
95+
impl<T: Type> fmt::Debug for Il2CppArray<T>
96+
where
97+
for<'a> T::Held<'a>: fmt::Debug,
98+
{
6599
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66-
f.debug_tuple("Il2CppArray").field(&self.as_ref()).finish()
100+
f.debug_tuple("Il2CppArray")
101+
.field(&self.as_slice())
102+
.finish()
67103
}
68104
}
69105

70-
impl<T> Deref for Il2CppArray<T> {
106+
impl<T: Type> Deref for Il2CppArray<T> {
71107
type Target = Il2CppObject;
72108

73109
fn deref(&self) -> &Self::Target {
74110
unsafe { Il2CppObject::wrap(&self.raw().obj) }
75111
}
76112
}
77113

78-
impl<T> DerefMut for Il2CppArray<T> {
114+
impl<T: Type> DerefMut for Il2CppArray<T> {
79115
fn deref_mut(&mut self) -> &mut Self::Target {
80116
unsafe { Il2CppObject::wrap_mut(&mut self.raw_mut().obj) }
81117
}
82118
}
83-
84-
impl<T> AsRef<[T]> for Il2CppArray<T> {
85-
fn as_ref(&self) -> &[T] {
86-
self.as_slice()
87-
}
88-
}
89-
90-
impl<T> AsMut<[T]> for Il2CppArray<T> {
91-
fn as_mut(&mut self) -> &mut [T] {
92-
self.as_mut_slice()
93-
}
94-
}

libil2cpp/src/field_info.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ffi::CStr;
33
use std::fmt;
44
use std::mem::MaybeUninit;
55

6-
use crate::{raw, Argument, Il2CppClass, Il2CppObject, Il2CppType, Returned, WrapRaw};
6+
use crate::{raw, Argument, Il2CppClass, Il2CppObject, Il2CppType, Type, WrapRaw};
77

88
/// Information about a C# field
99
#[repr(transparent)]
@@ -16,10 +16,7 @@ impl FieldInfo {
1616
A: Argument,
1717
{
1818
assert!(A::matches(self.ty()));
19-
20-
unsafe {
21-
self.store_unchecked(instance, val);
22-
}
19+
unsafe { self.store_unchecked(instance, val) };
2320
}
2421

2522
/// Store a value into a field without type checking
@@ -34,24 +31,23 @@ impl FieldInfo {
3431
}
3532

3633
/// Load a typechecked value from a field
37-
pub fn load<R>(&self, instance: &mut Il2CppObject) -> R
34+
pub fn load<'a, T>(&self, instance: &'a mut Il2CppObject) -> T::Held<'a>
3835
where
39-
R: Returned,
36+
T: Type,
4037
{
41-
assert!(R::matches(self.ty()));
42-
43-
unsafe { self.load_unchecked(instance) }
38+
assert!(T::class().is_assignable_from(self.ty().class()));
39+
unsafe { self.load_unchecked::<T>(instance) }
4440
}
4541

4642
/// Load a value from a field without type checking
4743
///
4844
/// # Safety
4945
/// To be safe, the provided type has to match the field signature
50-
pub unsafe fn load_unchecked<R>(&self, instance: &mut Il2CppObject) -> R
46+
pub unsafe fn load_unchecked<'a, T>(&self, instance: &'a mut Il2CppObject) -> T::Held<'a>
5147
where
52-
R: Returned,
48+
T: Type,
5349
{
54-
let mut val: MaybeUninit<R> = MaybeUninit::uninit();
50+
let mut val: MaybeUninit<T::Held<'a>> = MaybeUninit::uninit();
5551
raw::field_get_value(instance.raw_mut(), self.raw(), val.as_mut_ptr().cast());
5652
val.assume_init()
5753
}

libil2cpp/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![feature(once_cell, generic_associated_types)]
1+
#![feature(once_cell, generic_associated_types, never_type)]
22
#![doc(html_root_url = "https://stackdoubleflow.github.io/quest-hook-rs/libil2cpp")]
33
#![warn(
44
clippy::all,
@@ -114,4 +114,4 @@ pub use string::Il2CppString;
114114
pub use ty::{Builtin, Il2CppReflectionType, Il2CppType};
115115
pub use typecheck::callee::{Parameter, Parameters, Return, ThisParameter};
116116
pub use typecheck::caller::{Argument, Arguments, Returned, ThisArgument};
117-
pub use typecheck::ty::{Reference, Type, Value};
117+
pub use typecheck::ty::Type;

libil2cpp/src/object.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::fmt;
22

3-
use crate::{raw, Argument, Arguments, Il2CppClass, Il2CppException, Returned, WrapRaw};
3+
use crate::{raw, Argument, Arguments, Il2CppClass, Il2CppException, Returned, Type, WrapRaw};
44

55
/// An il2cpp object
66
#[repr(transparent)]
@@ -55,12 +55,12 @@ impl Il2CppObject {
5555
/// # Panics
5656
///
5757
/// This method will panic if the given field can't be found
58-
pub fn load<R>(&mut self, field: &str) -> R
58+
pub fn load<T>(&mut self, field: &str) -> T::Held<'_>
5959
where
60-
R: Returned,
60+
T: Type,
6161
{
6262
let field = self.class().find_field(field).unwrap();
63-
field.load(self)
63+
field.load::<T>(self)
6464
}
6565

6666
/// Stores a given value into a field of `self` with the given name, with

libil2cpp/src/raw/functions.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ il2cpp_functions! {
2626
pub fn method_get_object(method: &MethodInfo, refclass: Option<&Il2CppClass>) -> &'static Il2CppReflectionMethod;
2727
pub fn method_get_from_reflection(method: &Il2CppReflectionMethod) -> &'static MethodInfo;
2828
pub fn method_is_generic(method: &MethodInfo) -> bool;
29-
pub fn array_new(elem_type: &Il2CppClass, length: usize) -> *mut Il2CppArray;
29+
pub fn array_new(element_class: &Il2CppClass, length: usize) -> Option<&'static mut Il2CppArray>;
30+
pub fn array_class_get(element_class: &Il2CppClass, rank: u32, bounded: bool) -> &'static Il2CppClass;
3031
pub fn type_get_name(ty: &Il2CppType) -> *const c_char;
3132
pub fn type_get_object(ty: &Il2CppType) -> &'static Il2CppReflectionType;
3233
pub fn runtime_invoke(method: &MethodInfo, instance: *mut c_void, params: *mut *mut c_void, exception: &mut Option<&mut Il2CppException>) -> Option<&'static mut Il2CppObject>;

libil2cpp/src/typecheck/callee.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use std::fmt;
22

33
use crate::{Builtin, Il2CppType, MethodInfo, Type};
44

5-
use super::ty::semantics;
6-
75
/// Trait implemented by types that can be used as C# `this` method parameters
86
///
97
/// # Note
@@ -125,20 +123,25 @@ where
125123
}
126124

127125
unsafe impl ThisParameter for () {
128-
type Actual = ();
126+
type Actual = !;
129127

130128
fn matches(method: &MethodInfo) -> bool {
131129
method.is_static()
132130
}
133131

134-
fn from_actual((): ()) {}
135-
fn into_actual(self) {}
132+
fn from_actual(_: !) {
133+
unreachable!();
134+
}
135+
fn into_actual(self) -> ! {
136+
unreachable!()
137+
}
136138
}
137139

138-
unsafe impl<T, S> Parameter for Option<&mut T>
140+
// TODO: Remove this once rustfmt stops dropping generics on GATs
141+
#[rustfmt::skip]
142+
unsafe impl<T> Parameter for Option<&mut T>
139143
where
140-
T: Type<Semantics = S>,
141-
S: semantics::ReferenceParameter,
144+
T: for<'a> Type<Held<'a> = Option<&'a mut T>>,
142145
{
143146
type Actual = Self;
144147

@@ -154,10 +157,11 @@ where
154157
}
155158
}
156159

157-
unsafe impl<T, S> Parameter for &mut T
160+
// TODO: Remove this once rustfmt stops dropping generics on GATs
161+
#[rustfmt::skip]
162+
unsafe impl<T> Parameter for &mut T
158163
where
159-
T: Type<Semantics = S>,
160-
S: semantics::ReferenceParameter,
164+
T: for<'a> Type<Held<'a> = Option<&'a mut T>>,
161165
{
162166
type Actual = Option<Self>;
163167

@@ -173,15 +177,16 @@ where
173177
}
174178
}
175179

176-
unsafe impl<T, S> Return for Option<&mut T>
180+
// TODO: Remove this once rustfmt stops dropping generics on GATs
181+
#[rustfmt::skip]
182+
unsafe impl<T> Return for Option<&mut T>
177183
where
178-
T: Type<Semantics = S>,
179-
S: semantics::ReferenceReturn,
184+
T: for<'a> Type<Held<'a> = Option<&'a mut T>>,
180185
{
181186
type Actual = Self;
182187

183188
fn matches(ty: &Il2CppType) -> bool {
184-
T::matches_reference_return(ty)
189+
T::matches_return(ty)
185190
}
186191

187192
fn into_actual(self) -> Self::Actual {
@@ -192,15 +197,16 @@ where
192197
}
193198
}
194199

195-
unsafe impl<T, S> Return for &mut T
200+
// TODO: Remove this once rustfmt stops dropping generics on GATs
201+
#[rustfmt::skip]
202+
unsafe impl<T> Return for &mut T
196203
where
197-
T: Type<Semantics = S>,
198-
S: semantics::ReferenceReturn,
204+
T: for<'a> Type<Held<'a> = Option<&'a mut T>>,
199205
{
200206
type Actual = Option<Self>;
201207

202208
fn matches(ty: &Il2CppType) -> bool {
203-
T::matches_reference_return(ty)
209+
T::matches_return(ty)
204210
}
205211

206212
fn into_actual(self) -> Self::Actual {

0 commit comments

Comments
 (0)