mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-18 16:10:26 +02:00
Moving corlib files out of "System" directory into root
This commit is contained in:
parent
4cd58262e4
commit
7dbfd15292
179 changed files with 3 additions and 0 deletions
87
BeefLibs/corlib/src/Reflection/AttributeInfo.bf
Normal file
87
BeefLibs/corlib/src/Reflection/AttributeInfo.bf
Normal file
|
@ -0,0 +1,87 @@
|
|||
namespace System.Reflection
|
||||
{
|
||||
class AttributeInfo
|
||||
{
|
||||
static mixin Decode<T2>(void* data)
|
||||
{
|
||||
*((*(T2**)&data)++)
|
||||
}
|
||||
|
||||
public static Result<void> GetCustomAttribute(void* inAttrData, Type attributeType, Object targetAttr)
|
||||
{
|
||||
|
||||
TypeId findTypeId = attributeType.mTypeId;
|
||||
|
||||
void* data = inAttrData;
|
||||
data++;
|
||||
|
||||
uint8 count = Decode!<uint8>(data);
|
||||
for (int32 attrIdx = 0; attrIdx < count; attrIdx++)
|
||||
AttrBlock:
|
||||
{
|
||||
void* startPtr = data;
|
||||
var len = Decode!<uint16>(data);
|
||||
void* endPtr = (uint8*)startPtr + len;
|
||||
|
||||
var typeId = Decode!<TypeId>(data);
|
||||
if (typeId != findTypeId)
|
||||
{
|
||||
data = endPtr;
|
||||
continue;
|
||||
}
|
||||
|
||||
var methodIdx = Decode!<uint16>(data);
|
||||
|
||||
Type attrType = Type.GetType(typeId);
|
||||
TypeInstance attrTypeInst = attrType as TypeInstance;
|
||||
MethodInfo methodInfo = .(attrTypeInst, attrTypeInst.mMethodDataPtr + methodIdx);
|
||||
|
||||
Object[] args = scope Object[methodInfo.mMethodData.mParamCount];
|
||||
|
||||
int argIdx = 0;
|
||||
while (data < endPtr)
|
||||
{
|
||||
var attrDataType = Decode!<TypeCode>(data);
|
||||
switch (attrDataType)
|
||||
{
|
||||
case .Int8,
|
||||
.UInt8,
|
||||
.Char8:
|
||||
let attrData = Decode!<int8>(data);
|
||||
args[argIdx] = scope:AttrBlock box attrData;
|
||||
case .Int16,
|
||||
.UInt16,
|
||||
.Char16:
|
||||
let attrData = Decode!<int16>(data);
|
||||
args[argIdx] = scope:AttrBlock box attrData;
|
||||
case .Int32,
|
||||
.UInt32,
|
||||
.Char32:
|
||||
let attrData = Decode!<int32>(data);
|
||||
args[argIdx] = scope:AttrBlock box attrData;
|
||||
case .Float:
|
||||
let attrData = Decode!<float>(data);
|
||||
args[argIdx] = scope:AttrBlock box attrData;
|
||||
case .Int64,
|
||||
.UInt64,
|
||||
.Double:
|
||||
let attrData = Decode!<int64>(data);
|
||||
args[argIdx] = scope:AttrBlock box attrData;
|
||||
case (TypeCode)255:
|
||||
let stringId = Decode!<int32>(data);
|
||||
String str = String.[Friend]sIdStringLiterals[stringId];
|
||||
args[argIdx] = str;
|
||||
default:
|
||||
Runtime.FatalError("Not handled");
|
||||
}
|
||||
argIdx++;
|
||||
}
|
||||
|
||||
methodInfo.Invoke(targetAttr, params args);
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
return .Err;
|
||||
}
|
||||
}
|
||||
}
|
65
BeefLibs/corlib/src/Reflection/BindingFlags.bf
Normal file
65
BeefLibs/corlib/src/Reflection/BindingFlags.bf
Normal file
|
@ -0,0 +1,65 @@
|
|||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BindingFlags are a set of flags that control the binding and invocation process
|
||||
//
|
||||
// <OWNER>[....]</OWNER>
|
||||
// in Reflection. There are two processes. The first is selection of a Member which
|
||||
// is the binding phase. The second, is invocation. These flags control how this
|
||||
// process works.
|
||||
//
|
||||
// <EMAIL>Author: darylo</EMAIL>
|
||||
// Date: June 99
|
||||
//
|
||||
namespace System.Reflection
|
||||
{
|
||||
using System;
|
||||
public enum BindingFlags
|
||||
{
|
||||
|
||||
// NOTES: We have lookup masks defined in RuntimeType and Activator. If we
|
||||
// change the lookup values then these masks may need to change also.
|
||||
|
||||
// a place holder for no flag specifed
|
||||
Default = 0x00,
|
||||
|
||||
// These flags indicate what to search for when binding
|
||||
IgnoreCase = 0x01, // Ignore the case of Names while searching
|
||||
DeclaredOnly = 0x02, // Only look at the members declared on the Type
|
||||
Instance = 0x04, // Include Instance members in search
|
||||
Static = 0x08, // Include Static members in search
|
||||
Public = 0x10, // Include Public members in search
|
||||
NonPublic = 0x20, // Include Non-Public members in search
|
||||
FlattenHierarchy = 0x40, // Rollup the statics into the class.
|
||||
|
||||
// These flags are used by InvokeMember to determine
|
||||
// what type of member we are trying to Invoke.
|
||||
// BindingAccess = 0xFF00;
|
||||
InvokeMethod = 0x0100,
|
||||
CreateInstance = 0x0200,
|
||||
GetField = 0x0400,
|
||||
SetField = 0x0800,
|
||||
GetProperty = 0x1000,
|
||||
SetProperty = 0x2000,
|
||||
|
||||
// These flags are also used by InvokeMember but they should only
|
||||
// be used when calling InvokeMember on a COM object.
|
||||
PutDispProperty = 0x4000,
|
||||
PutRefDispProperty = 0x8000,
|
||||
|
||||
ExactBinding = 0x010000, // Bind with Exact Type matching, No Change type
|
||||
SuppressChangeType = 0x020000,
|
||||
|
||||
// DefaultValueBinding will return the set of methods having ArgCount or
|
||||
// more parameters. This is used for default values, etc.
|
||||
OptionalParamBinding = 0x040000,
|
||||
|
||||
// These are a couple of misc attributes used
|
||||
IgnoreReturn = 0x01000000, // This is used in COM Interop
|
||||
}
|
||||
}
|
101
BeefLibs/corlib/src/Reflection/Convert.bf
Normal file
101
BeefLibs/corlib/src/Reflection/Convert.bf
Normal file
|
@ -0,0 +1,101 @@
|
|||
namespace System.Reflection
|
||||
{
|
||||
static class Convert
|
||||
{
|
||||
static (Type type, void* ptr) GetTypeAndPointer(Object obj)
|
||||
{
|
||||
var objType = obj.RawGetType();
|
||||
void* dataPtr = (uint8*)Internal.UnsafeCastToPtr(obj) + objType.mMemberDataOffset;
|
||||
if (objType.IsBoxed)
|
||||
objType = objType.UnderlyingType;
|
||||
if (objType.IsTypedPrimitive)
|
||||
objType = objType.UnderlyingType;
|
||||
return (objType, dataPtr);
|
||||
}
|
||||
|
||||
public static Result<int64> ToInt64(Object obj)
|
||||
{
|
||||
var (objType, dataPtr) = GetTypeAndPointer(obj);
|
||||
switch (objType.mTypeCode)
|
||||
{
|
||||
case .Int8: return (.)*(int8*)dataPtr;
|
||||
case .Int16: return (.)*(int16*)dataPtr;
|
||||
case .Int32: return (.)*(int32*)dataPtr;
|
||||
case .Int64: return (.)*(int64*)dataPtr;
|
||||
case .UInt8, .Char8: return (.)*(uint8*)dataPtr;
|
||||
case .UInt16, .Char16: return (.)*(uint16*)dataPtr;
|
||||
case .UInt32, .Char32: return (.)*(uint32*)dataPtr;
|
||||
case .UInt64: return (.)*(uint64*)dataPtr;
|
||||
case .Int: return (.)*(int*)dataPtr;
|
||||
case .UInt: return (.)*(uint*)dataPtr;
|
||||
default: return .Err;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IntCanFit(int64 val, Type type)
|
||||
{
|
||||
switch (type.mTypeCode)
|
||||
{
|
||||
case .Int8: return (val >= -0x80) && (val <= 0x7F);
|
||||
case .Int16: return (val >= -0x8000) && (val <= 0x7FFF);
|
||||
case .Int32: return (val >= -0x80000000) && (val <= 0x7FFF'FFFF);
|
||||
case .Int64: return (val >= -0x80000000'00000000) && (val <= 0x7FFFFFFF'FFFFFFFF);
|
||||
case .UInt8, .Char8: return (val >= 0) && (val <= 0xFF);
|
||||
case .UInt16, .Char16: return (val >= 0) && (val <= 0xFFFF);
|
||||
case .UInt32, .Char32: return (val >= 0) && (val <= 0xFFFFFFFF);
|
||||
case .UInt64: return (val >= 0) && (val <= 0x7FFFFFFF'FFFFFFFF);
|
||||
#if BF_64_BIT
|
||||
case .Int: return (val >= -0x80000000'00000000) && (val <= 0x7FFFFFFF'FFFFFFFF);
|
||||
case .UInt: return (val >= 0) && (val <= 0x7FFFFFFF'FFFFFFFF);
|
||||
#else
|
||||
case .Int: return (val >= -0x80000000) && (val <= 0x7FFF'FFFF);
|
||||
case .UInt: return (val >= 0) && (val <= 0xFFFFFFFF);
|
||||
#endif
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Result<Variant> ConvertTo(Object obj, Type type)
|
||||
{
|
||||
if (obj.GetType() == type)
|
||||
{
|
||||
return Variant.Create(obj, false);
|
||||
}
|
||||
|
||||
var (objType, dataPtr) = GetTypeAndPointer(obj);
|
||||
if (objType.IsPrimitive)
|
||||
{
|
||||
if (objType.IsInteger)
|
||||
{
|
||||
int64 intVal = ToInt64(obj);
|
||||
switch (type.mTypeCode)
|
||||
{
|
||||
case .Float:
|
||||
float val = (.)intVal;
|
||||
return Variant.Create(type, &val);
|
||||
case .Double:
|
||||
double val = (.)intVal;
|
||||
return Variant.Create(type, &val);
|
||||
default:
|
||||
}
|
||||
|
||||
if (IntCanFit(intVal, type))
|
||||
{
|
||||
return Variant.Create(type, &intVal);
|
||||
}
|
||||
}
|
||||
else if (objType.IsFloatingPoint)
|
||||
{
|
||||
if ((type.mTypeCode == .Double) &&
|
||||
(objType.mTypeCode == .Float))
|
||||
{
|
||||
double val = (.)*(float*)dataPtr;
|
||||
return Variant.Create(type, &val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .Err;
|
||||
}
|
||||
}
|
||||
}
|
390
BeefLibs/corlib/src/Reflection/FieldInfo.bf
Normal file
390
BeefLibs/corlib/src/Reflection/FieldInfo.bf
Normal file
|
@ -0,0 +1,390 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Reflection
|
||||
{
|
||||
[CRepr, AlwaysInclude]
|
||||
public struct FieldInfo
|
||||
{
|
||||
public enum Error
|
||||
{
|
||||
InvalidTargetType,
|
||||
InvalidValueType
|
||||
}
|
||||
|
||||
internal TypeInstance mTypeInstance;
|
||||
internal TypeInstance.FieldData* mFieldData;
|
||||
|
||||
public this(TypeInstance typeInstance, TypeInstance.FieldData* fieldData)
|
||||
{
|
||||
mTypeInstance = typeInstance;
|
||||
mFieldData = fieldData;
|
||||
}
|
||||
|
||||
public int32 MemberOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return mFieldData.mDataOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public Type FieldType
|
||||
{
|
||||
get
|
||||
{
|
||||
return Type.GetType(mFieldData.mFieldTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
public StringView Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return mFieldData.mName;
|
||||
}
|
||||
}
|
||||
|
||||
public Result<void, Error> SetValue(Object obj, Object value)
|
||||
{
|
||||
int32 dataOffsetAdjust = 0;
|
||||
if (mTypeInstance.IsStruct)
|
||||
{
|
||||
Type boxedType = obj.RawGetType();
|
||||
bool typeMatched = false;
|
||||
if (boxedType.IsBoxed)
|
||||
{
|
||||
if (mTypeInstance == boxedType.UnderlyingType)
|
||||
{
|
||||
dataOffsetAdjust = boxedType.mMemberDataOffset;
|
||||
typeMatched = true;
|
||||
}
|
||||
}
|
||||
if (!typeMatched)
|
||||
return .Err(.InvalidTargetType); // "Invalid target type");
|
||||
}
|
||||
|
||||
Type fieldType = Type.GetType(mFieldData.mFieldTypeId);
|
||||
//Type objType = obj.GetType();
|
||||
|
||||
void* dataAddr = ((uint8*)(void*)obj) + mFieldData.mDataOffset + dataOffsetAdjust;
|
||||
|
||||
switch (fieldType.mTypeCode)
|
||||
{
|
||||
case .Boolean:
|
||||
if (!value is bool)
|
||||
return .Err(.InvalidValueType);
|
||||
*(bool*)(uint8*)dataAddr = (.)value;
|
||||
break;
|
||||
case .Int32:
|
||||
if (!value is int32)
|
||||
return .Err(.InvalidValueType);
|
||||
*(int32*)(uint8*)dataAddr = (.)value;
|
||||
break;
|
||||
default:
|
||||
return .Err(.InvalidValueType);
|
||||
}
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
public Result<void> SetValue(Object obj, Variant value)
|
||||
{
|
||||
int32 dataOffsetAdjust = 0;
|
||||
if (mTypeInstance.IsStruct)
|
||||
{
|
||||
Type boxedType = obj.RawGetType();
|
||||
bool typeMatched = false;
|
||||
if (boxedType.IsBoxed)
|
||||
{
|
||||
if (mTypeInstance == boxedType.UnderlyingType)
|
||||
{
|
||||
dataOffsetAdjust = boxedType.mMemberDataOffset;
|
||||
typeMatched = true;
|
||||
}
|
||||
}
|
||||
if (!typeMatched)
|
||||
return .Err;//("Invalid target type");
|
||||
}
|
||||
|
||||
Type fieldType = Type.GetType(mFieldData.mFieldTypeId);
|
||||
//Type objType = obj.GetType();
|
||||
|
||||
void* dataAddr = ((uint8*)(void*)obj) + mFieldData.mDataOffset + dataOffsetAdjust;
|
||||
|
||||
if (value.VariantType != fieldType)
|
||||
return .Err;//("Invalid type");
|
||||
|
||||
value.CopyValueData(dataAddr);
|
||||
|
||||
//TypeCode typeCode = fieldType.mTypeCode;
|
||||
|
||||
/*if (typeCode == TypeCode.Enum)
|
||||
typeCode = fieldType.GetUnderlyingType().mTypeCode;
|
||||
|
||||
switch (typeCode)
|
||||
{
|
||||
case TypeCode.Int32:
|
||||
*(int32*)dataAddr = value.Get<int32>();
|
||||
break;
|
||||
case TypeCode.Boolean:
|
||||
*(bool*)dataAddr = value.Get<bool>();
|
||||
break;
|
||||
case TypeCode.Object:
|
||||
*(Object*)dataAddr = value.Get<Object>();
|
||||
break;
|
||||
default:
|
||||
return .Err;//("Invalid type");
|
||||
}*/
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
static mixin Decode<T2>(void* data)
|
||||
{
|
||||
*((*(T2**)&data)++)
|
||||
}
|
||||
|
||||
public Result<T> GetCustomAttribute<T>() where T : Attribute
|
||||
{
|
||||
if (mFieldData.mCustomAttributesIdx == -1)
|
||||
return .Err;
|
||||
|
||||
void* data = mTypeInstance.mCustomAttrDataPtr[mFieldData.mCustomAttributesIdx];
|
||||
|
||||
T attrInst = ?;
|
||||
switch (AttributeInfo.GetCustomAttribute(data, typeof(T), &attrInst))
|
||||
{
|
||||
case .Ok: return .Ok(attrInst);
|
||||
default:
|
||||
return .Err;
|
||||
}
|
||||
}
|
||||
|
||||
void* GetDataPtrAndType(Object value, out Type type)
|
||||
{
|
||||
type = value.RawGetType();
|
||||
/*if (type.IsStruct)
|
||||
return &value;*/
|
||||
|
||||
if (type.IsStruct)
|
||||
{
|
||||
NOP!();
|
||||
}
|
||||
|
||||
if (type.IsBoxed)
|
||||
return ((uint8*)(void*)value) + type.mMemberDataOffset;
|
||||
return ((uint8*)(void*)value);
|
||||
}
|
||||
|
||||
public Result<void> GetValue<TMember>(Object target, out TMember value)
|
||||
{
|
||||
value = default(TMember);
|
||||
|
||||
Type tTarget;
|
||||
void* targetDataAddr = GetDataPtrAndType(target, out tTarget);
|
||||
//Type tTarget = target.RawGetType();
|
||||
//void* targetDataAddr = (void*)⌖
|
||||
|
||||
Type tMember = typeof(TMember);
|
||||
|
||||
targetDataAddr = (uint8*)targetDataAddr + mFieldData.mDataOffset;
|
||||
|
||||
Type fieldType = Type.GetType(mFieldData.mFieldTypeId);
|
||||
|
||||
if (tMember.mTypeCode == TypeCode.Object)
|
||||
{
|
||||
if (!tTarget.IsSubtypeOf(mTypeInstance))
|
||||
Runtime.FatalError();
|
||||
value = *(TMember*)targetDataAddr;
|
||||
}
|
||||
else if (tMember.mTypeCode == TypeCode.Int32)
|
||||
{
|
||||
if (fieldType.mTypeCode == TypeCode.Int32)
|
||||
{
|
||||
if (tMember.mTypeCode != TypeCode.Int32)
|
||||
Runtime.FatalError("Expected int");
|
||||
*(int32*)&value = *(int32*)targetDataAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return .Err;//("Invalid type");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return .Err;//("Invalid type");
|
||||
}
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
public Result<Variant> GetValue(Object target)
|
||||
{
|
||||
Variant value = Variant();
|
||||
|
||||
Type tTarget;
|
||||
void* targetDataAddr = GetDataPtrAndType(target, out tTarget);
|
||||
//Type tTarget = target.RawGetType();
|
||||
//void* targetDataAddr = (void*)⌖
|
||||
|
||||
if (!tTarget.IsSubtypeOf(mTypeInstance))
|
||||
Runtime.FatalError("Invalid type");
|
||||
|
||||
targetDataAddr = (uint8*)targetDataAddr + mFieldData.mDataOffset;
|
||||
|
||||
Type fieldType = Type.GetType(mFieldData.mFieldTypeId);
|
||||
|
||||
/*if (fieldType.IsNullable)
|
||||
{
|
||||
var specializedType = (SpecializedGenericType)fieldType;
|
||||
var genericArg = specializedType.GetGenericArg(0);
|
||||
|
||||
bool hasValue = *(bool*)((uint8*)targetDataAddr + genericArg.mSize);
|
||||
if (!hasValue)
|
||||
return .Err;
|
||||
fieldType = genericArg;
|
||||
}*/
|
||||
|
||||
//value.mStructType = (int)(void*)fieldType;
|
||||
|
||||
TypeCode typeCode = fieldType.mTypeCode;
|
||||
if (typeCode == TypeCode.Enum)
|
||||
typeCode = fieldType.UnderlyingType.mTypeCode;
|
||||
|
||||
/*if (typeCode == TypeCode.Int32)
|
||||
{
|
||||
*(int32*)&value.mData = *(int32*)targetDataAddr;
|
||||
}
|
||||
else if (typeCode == TypeCode.Boolean)
|
||||
{
|
||||
*(bool*)&value.mData = *(bool*)targetDataAddr;
|
||||
}
|
||||
else */if (typeCode == TypeCode.Object)
|
||||
{
|
||||
value.mStructType = 0;
|
||||
value.mData = *(int*)targetDataAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Variant.Create(fieldType, targetDataAddr);
|
||||
}
|
||||
|
||||
/*else if (fieldType.mSize <= sizeof(int))
|
||||
{
|
||||
value.mStructType = (int)(void*)fieldType;
|
||||
Internal.MemCpy(&value.mData, targetDataAddr, fieldType.mSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
value.mStructType = (int)(void*)fieldType;
|
||||
void* data = new uint8[fieldType.mSize]*;
|
||||
Internal.MemCpy(data, targetDataAddr, fieldType.mSize);
|
||||
value.mData = (int)data;
|
||||
}*/
|
||||
/*{
|
||||
return .Err;
|
||||
}*/
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public Result<Variant> GetValue()
|
||||
{
|
||||
Variant value = Variant();
|
||||
|
||||
//TODO: Assert static
|
||||
|
||||
if (mFieldData.mFlags.HasFlag(FieldFlags.Const))
|
||||
{
|
||||
return Variant.Create(FieldType, &mFieldData.mConstValue);
|
||||
}
|
||||
|
||||
ThrowUnimplemented();
|
||||
|
||||
//Type tTarget;
|
||||
#unwarn
|
||||
void* targetDataAddr = (void*)(int)mFieldData.mConstValue;
|
||||
|
||||
Type fieldType = Type.GetType(mFieldData.mFieldTypeId);
|
||||
value.mStructType = (int)(void*)fieldType;
|
||||
|
||||
TypeCode typeCode = fieldType.mTypeCode;
|
||||
if (typeCode == TypeCode.Enum)
|
||||
typeCode = fieldType.UnderlyingType.mTypeCode;
|
||||
|
||||
if (typeCode == TypeCode.Int32)
|
||||
{
|
||||
*(int32*)&value.mData = *(int32*)targetDataAddr;
|
||||
}
|
||||
else if (typeCode == TypeCode.Object)
|
||||
{
|
||||
value.mStructType = 0;
|
||||
value.mData = (int)targetDataAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return .Err;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
internal struct Enumerator : IEnumerator<FieldInfo>
|
||||
{
|
||||
BindingFlags mBindingFlags;
|
||||
TypeInstance mTypeInstance;
|
||||
int32 mIdx;
|
||||
|
||||
internal this(TypeInstance typeInst, BindingFlags bindingFlags)
|
||||
{
|
||||
mTypeInstance = typeInst;
|
||||
mBindingFlags = bindingFlags;
|
||||
mIdx = -1;
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
mIdx = -1;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
if (mTypeInstance == null)
|
||||
return false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
mIdx++;
|
||||
if (mIdx == mTypeInstance.mFieldDataCount)
|
||||
return false;
|
||||
var fieldData = &mTypeInstance.mFieldDataPtr[mIdx];
|
||||
bool matches = (mBindingFlags.HasFlag(BindingFlags.Static) && (fieldData.mFlags.HasFlag(FieldFlags.Static)));
|
||||
matches |= (mBindingFlags.HasFlag(BindingFlags.Instance) && (!fieldData.mFlags.HasFlag(FieldFlags.Static)));
|
||||
if (matches)
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public FieldInfo Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var fieldData = &mTypeInstance.mFieldDataPtr[mIdx];
|
||||
return FieldInfo(mTypeInstance, fieldData);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<FieldInfo> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
412
BeefLibs/corlib/src/Reflection/MethodInfo.bf
Normal file
412
BeefLibs/corlib/src/Reflection/MethodInfo.bf
Normal file
|
@ -0,0 +1,412 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.FFI;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Reflection
|
||||
{
|
||||
[CRepr, AlwaysInclude]
|
||||
public struct MethodInfo
|
||||
{
|
||||
internal TypeInstance mTypeInstance;
|
||||
internal TypeInstance.MethodData* mMethodData;
|
||||
|
||||
public StringView Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return mMethodData.mName;
|
||||
}
|
||||
}
|
||||
|
||||
public int ParamCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return mMethodData.mParamCount;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsConstructor
|
||||
{
|
||||
get
|
||||
{
|
||||
// String pooling allows us to do identity comparison
|
||||
return (Object)mMethodData.mName == "__BfCtor" || ((Object)mMethodData.mName == "__BfStaticCtor");
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDestructor
|
||||
{
|
||||
get
|
||||
{
|
||||
// String pooling allows us to do identity comparison
|
||||
return (Object)mMethodData.mName == "__BfStaticDtor" || (Object)mMethodData.mName == "__BfStaticDtor";
|
||||
}
|
||||
}
|
||||
|
||||
public Type GetParamType(int paramIdx)
|
||||
{
|
||||
Debug.Assert((uint)paramIdx < (uint)mMethodData.mParamCount);
|
||||
return Type.GetType(mMethodData.mParamData[paramIdx].mType);
|
||||
}
|
||||
|
||||
public StringView GetParamName(int paramIdx)
|
||||
{
|
||||
Debug.Assert((uint)paramIdx < (uint)mMethodData.mParamCount);
|
||||
return mMethodData.mParamData[paramIdx].mName;
|
||||
}
|
||||
|
||||
public this(TypeInstance typeInstance, TypeInstance.MethodData* methodData)
|
||||
{
|
||||
mTypeInstance = typeInstance;
|
||||
mMethodData = methodData;
|
||||
}
|
||||
|
||||
public enum CallError
|
||||
{
|
||||
case None;
|
||||
case TargetExpected;
|
||||
case TargetNotExpected;
|
||||
case InvalidTarget;
|
||||
case InvalidArgument(int32 paramIdx);
|
||||
case ParamCountMismatch;
|
||||
case FFIError;
|
||||
}
|
||||
|
||||
public Result<Variant, CallError> Invoke(Object target, params Object[] args)
|
||||
{
|
||||
var retType = Type.GetType(mMethodData.mReturnType);
|
||||
|
||||
FFIABI abi = .Default;
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
if (mMethodData.mFlags.HasFlag(.StdCall))
|
||||
abi = .StdCall;
|
||||
#endif
|
||||
|
||||
List<FFIType*> ffiParamList = scope .(16);
|
||||
List<void*> ffiArgList = scope .(16);
|
||||
List<Variant> tempVariants = scope .(4);
|
||||
|
||||
var target;
|
||||
|
||||
mixin GetFFIType(Type type)
|
||||
{
|
||||
int wantSize = 0;
|
||||
FFIType* ffiType = FFIType.Get(type, null, &wantSize);
|
||||
if ((ffiType == null) && (wantSize != 0))
|
||||
{
|
||||
void* allocBytes = scope:mixin uint8[wantSize]*;
|
||||
ffiType = FFIType.Get(type, allocBytes, &wantSize);
|
||||
}
|
||||
|
||||
ffiType
|
||||
}
|
||||
|
||||
void SplatArg(TypeInstance type, void* ptr)
|
||||
{
|
||||
if (type.BaseType != null)
|
||||
SplatArg(type.BaseType, ptr);
|
||||
|
||||
bool isEnum = type.IsEnum;
|
||||
for (int fieldIdx < type.mFieldDataCount)
|
||||
{
|
||||
let fieldData = ref type.mFieldDataPtr[fieldIdx];
|
||||
let fieldType = Type.GetType(fieldData.mFieldTypeId);
|
||||
if (fieldData.mFlags.HasFlag(.Static))
|
||||
{
|
||||
if (isEnum)
|
||||
break; // Already got payload and discriminator
|
||||
continue;
|
||||
}
|
||||
if (fieldType.mSize == 0)
|
||||
continue;
|
||||
|
||||
if (fieldType.IsStruct)
|
||||
{
|
||||
SplatArg((TypeInstance)fieldType, (uint8*)ptr + fieldData.mDataOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffiParamList.Add(FFIType.Get(fieldType, null, null));
|
||||
ffiArgList.Add((uint8*)ptr + fieldData.mDataOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin AddArg(int argIdx, Object arg, void* argPtr, Type paramType, bool splat)
|
||||
{
|
||||
bool unbox = false;
|
||||
bool unboxToPtr = false;
|
||||
|
||||
let argType = arg.RawGetType();
|
||||
void* dataPtr = (uint8*)Internal.UnsafeCastToPtr(arg) + argType.mMemberDataOffset;
|
||||
bool isValid = true;
|
||||
|
||||
if (paramType.IsValueType)
|
||||
{
|
||||
bool handled = true;
|
||||
|
||||
if (!argType.IsBoxed)
|
||||
return .Err(.InvalidArgument((.)argIdx));
|
||||
|
||||
Type underlyingType = argType.UnderlyingType;
|
||||
if ((paramType.IsPrimitive) && (underlyingType.IsTypedPrimitive)) // Boxed primitive?
|
||||
underlyingType = underlyingType.UnderlyingType;
|
||||
if (!underlyingType.IsSubtypeOf(paramType))
|
||||
{
|
||||
if (underlyingType.IsGenericType)
|
||||
{
|
||||
var ptrTypedPrimitive = (SpecializedGenericType)underlyingType;
|
||||
if ((ptrTypedPrimitive.mTypeFlags.HasFlag(.Sys_PointerT)))
|
||||
{
|
||||
let elementType = Type.GetType(ptrTypedPrimitive.mResolvedTypeRefs[0]);
|
||||
if (elementType == paramType)
|
||||
{
|
||||
dataPtr = *(void**)dataPtr;
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if (underlyingType.IsSpecialType(TypeInstance.[Friend]sPointerTType, "System", "Pointer", 2))
|
||||
{
|
||||
|
||||
}*/
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
if (!underlyingType.IsSubtypeOf(paramType))
|
||||
{
|
||||
if (Convert.ConvertTo(arg, paramType) case .Ok(var variant))
|
||||
{
|
||||
tempVariants.Add(variant);
|
||||
dataPtr = variant.GetValueData();
|
||||
}
|
||||
else
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!argType.IsSubtypeOf(paramType))
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!isValid)
|
||||
{
|
||||
if (argIdx == -1)
|
||||
return .Err(.InvalidTarget);
|
||||
else
|
||||
return .Err(.InvalidArgument((.)argIdx));
|
||||
}
|
||||
|
||||
if (paramType.IsStruct)
|
||||
{
|
||||
TypeInstance paramTypeInst = (TypeInstance)paramType;
|
||||
|
||||
if (paramType.Size == 0)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else if (splat)
|
||||
{
|
||||
if (paramTypeInst.mFieldDataCount > 0)
|
||||
{
|
||||
SplatArg(paramTypeInst, dataPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
let splatData = (TypeInstance.FieldSplatData*)paramTypeInst.mFieldDataPtr;
|
||||
for (int splatIdx < 3)
|
||||
{
|
||||
let splatTypeId = splatData.mSplatTypes[splatIdx];
|
||||
if (splatTypeId == 0)
|
||||
break;
|
||||
|
||||
let splatType = Type.GetType(splatTypeId);
|
||||
ffiParamList.Add(GetFFIType!:mixin(splatType));
|
||||
ffiArgList.Add((uint8*)dataPtr + splatData.mSplatOffsets[splatIdx]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pass by ref
|
||||
ffiParamList.Add(&FFIType.Pointer);
|
||||
unboxToPtr = true;
|
||||
unbox = true;
|
||||
}
|
||||
}
|
||||
else if (paramType.IsValueType)
|
||||
{
|
||||
ffiParamList.Add(GetFFIType!:mixin(paramType));
|
||||
unbox = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffiParamList.Add(&FFIType.Pointer);
|
||||
ffiArgList.Add(argPtr);
|
||||
}
|
||||
|
||||
if (unbox)
|
||||
{
|
||||
if (unboxToPtr)
|
||||
{
|
||||
int* stackDataPtr = scope:mixin int;
|
||||
*stackDataPtr = (int)dataPtr;
|
||||
ffiArgList.Add(stackDataPtr);
|
||||
}
|
||||
else
|
||||
ffiArgList.Add(dataPtr);
|
||||
}
|
||||
}
|
||||
|
||||
if (mMethodData.mFlags.HasFlag(.Static))
|
||||
{
|
||||
if (target != null)
|
||||
return .Err(.TargetNotExpected);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target == null)
|
||||
return .Err(.TargetExpected);
|
||||
|
||||
bool splatThis = mTypeInstance.IsSplattable && !mMethodData.mFlags.HasFlag(.Mutating);
|
||||
AddArg!::(-1, target, &target, mTypeInstance, splatThis);
|
||||
}
|
||||
|
||||
if (args.Count != mMethodData.mParamCount)
|
||||
return .Err(.ParamCountMismatch);
|
||||
|
||||
Variant retVal;
|
||||
void* variantData = Variant.Alloc(retType, out retVal);
|
||||
void* retData = variantData;
|
||||
|
||||
// Struct return? Manually add it as an arg after 'this'. Revisit this - this is architecture-dependent.
|
||||
int unusedRetVal;
|
||||
FFIType* ffiRetType = null;
|
||||
if (retType.IsStruct)
|
||||
{
|
||||
ffiRetType = &FFIType.Void;
|
||||
ffiParamList.Add(&FFIType.Pointer);
|
||||
ffiArgList.Add(&variantData);
|
||||
retData = &unusedRetVal;
|
||||
}
|
||||
else
|
||||
ffiRetType = GetFFIType!::(retType);
|
||||
|
||||
for (var arg in ref args)
|
||||
{
|
||||
let paramData = ref mMethodData.mParamData[@arg];
|
||||
let argType = Type.GetType(paramData.mType);
|
||||
AddArg!::(@arg, arg, &arg, argType, paramData.mParamFlags.HasFlag(.Splat));
|
||||
}
|
||||
|
||||
FFICaller caller = .();
|
||||
if (ffiParamList.Count > 0)
|
||||
{
|
||||
if (caller.Prep(abi, (.)ffiParamList.Count, ffiRetType, &ffiParamList[0]) case .Err)
|
||||
return .Err(.FFIError);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (caller.Prep(abi, 0, ffiRetType, null) case .Err)
|
||||
return .Err(.FFIError);
|
||||
}
|
||||
|
||||
void* funcPtr = mMethodData.mFuncPtr;
|
||||
if (mMethodData.mFlags.HasFlag(.Virtual))
|
||||
{
|
||||
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
|
||||
void* classVData = (void*)(target.[Friend]mClassVData & ~0xFF);
|
||||
#else
|
||||
void* classVData = target.[Friend]mClassVData;
|
||||
#endif
|
||||
if (mMethodData.mVirtualIdx >= 0x100000)
|
||||
{
|
||||
void* extAddr = (void*)*((int*)classVData + (mMethodData.mVirtualIdx>>20 - 1));
|
||||
funcPtr = (void*)*((int*)extAddr + (mMethodData.mVirtualIdx & 0xFFFFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
funcPtr = (void*)*(int*)((uint8*)classVData + mMethodData.mVirtualIdx);
|
||||
}
|
||||
}
|
||||
|
||||
if (ffiArgList.Count > 0)
|
||||
caller.Call(funcPtr, retData, &ffiArgList[0]);
|
||||
else
|
||||
caller.Call(funcPtr, retData, null);
|
||||
|
||||
for (var variant in ref tempVariants)
|
||||
variant.Dispose();
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
internal struct Enumerator : IEnumerator<MethodInfo>
|
||||
{
|
||||
BindingFlags mBindingFlags;
|
||||
TypeInstance mTypeInstance;
|
||||
int32 mIdx;
|
||||
|
||||
internal this(TypeInstance typeInst, BindingFlags bindingFlags)
|
||||
{
|
||||
mTypeInstance = typeInst;
|
||||
mBindingFlags = bindingFlags;
|
||||
mIdx = -1;
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
mIdx = -1;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
if (mTypeInstance == null)
|
||||
return false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
mIdx++;
|
||||
if (mIdx == mTypeInstance.mMethodDataCount)
|
||||
return false;
|
||||
#unwarn
|
||||
var methodData = &mTypeInstance.mMethodDataPtr[mIdx];
|
||||
/*bool matches = (mBindingFlags.HasFlag(BindingFlags.Static) && (methodData.mFlags.HasFlag(FieldFlags.Static)));
|
||||
matches |= (mBindingFlags.HasFlag(BindingFlags.Instance) && (!methodData.mFlags.HasFlag(FieldFlags.Static)));*/
|
||||
bool matches = true;
|
||||
if (matches)
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public MethodInfo Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var methodData = &mTypeInstance.mMethodDataPtr[mIdx];
|
||||
return MethodInfo(mTypeInstance, methodData);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<MethodInfo> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
63
BeefLibs/corlib/src/Reflection/TypeInstance.bf
Normal file
63
BeefLibs/corlib/src/Reflection/TypeInstance.bf
Normal file
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace System
|
||||
{
|
||||
extension Type
|
||||
{
|
||||
public enum MethodError
|
||||
{
|
||||
NoResults,
|
||||
MultipleResults
|
||||
}
|
||||
|
||||
public virtual MethodInfo.Enumerator GetMethods(BindingFlags bindingFlags = cDefaultLookup)
|
||||
{
|
||||
return MethodInfo.Enumerator(null, bindingFlags);
|
||||
}
|
||||
|
||||
public virtual Result<MethodInfo, MethodError> GetMethod(StringView methodName, BindingFlags bindingFlags = cDefaultLookup)
|
||||
{
|
||||
MethodInfo matched = default;
|
||||
for (let methodInfo in GetMethods(bindingFlags))
|
||||
{
|
||||
if (methodInfo.mMethodData.mName == methodName)
|
||||
{
|
||||
if (matched.mMethodData != null)
|
||||
return .Err(.MultipleResults);
|
||||
}
|
||||
}
|
||||
|
||||
if (matched.mMethodData == null)
|
||||
return .Err(.NoResults);
|
||||
return .Ok(matched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace System.Reflection
|
||||
{
|
||||
extension TypeInstance
|
||||
{
|
||||
public override FieldInfo? GetField(String fieldName)
|
||||
{
|
||||
for (int32 i = 0; i < mFieldDataCount; i++)
|
||||
{
|
||||
FieldData* fieldData = &mFieldDataPtr[i];
|
||||
if (fieldData.mName == fieldName)
|
||||
return FieldInfo(this, fieldData);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override FieldInfo.Enumerator GetFields(BindingFlags bindingFlags = cDefaultLookup)
|
||||
{
|
||||
return FieldInfo.Enumerator(this, bindingFlags);
|
||||
}
|
||||
|
||||
public override MethodInfo.Enumerator GetMethods(BindingFlags bindingFlags = cDefaultLookup)
|
||||
{
|
||||
return MethodInfo.Enumerator(this, bindingFlags);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue