2020-04-29 06:40:03 -07:00
|
|
|
using System.Collections;
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
namespace System.Reflection
|
|
|
|
{
|
|
|
|
[CRepr, AlwaysInclude]
|
|
|
|
public struct FieldInfo
|
|
|
|
{
|
|
|
|
public enum Error
|
|
|
|
{
|
|
|
|
InvalidTargetType,
|
|
|
|
InvalidValueType
|
|
|
|
}
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
TypeInstance mTypeInstance;
|
|
|
|
TypeInstance.FieldData* mFieldData;
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
public this(TypeInstance typeInstance, TypeInstance.FieldData* fieldData)
|
|
|
|
{
|
|
|
|
mTypeInstance = typeInstance;
|
|
|
|
mFieldData = fieldData;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int32 MemberOffset
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mFieldData.mDataOffset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Type FieldType
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
return Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public StringView Name
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mFieldData.mName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<void, Error> SetValue(Object obj, Object value)
|
|
|
|
{
|
|
|
|
int32 dataOffsetAdjust = 0;
|
|
|
|
if (mTypeInstance.IsStruct)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
Type boxedType = obj.[Friend]RawGetType();
|
2019-08-23 11:56:54 -07:00
|
|
|
bool typeMatched = false;
|
|
|
|
if (boxedType.IsBoxed)
|
|
|
|
{
|
|
|
|
if (mTypeInstance == boxedType.UnderlyingType)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
dataOffsetAdjust = boxedType.[Friend]mMemberDataOffset;
|
2019-08-23 11:56:54 -07:00
|
|
|
typeMatched = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!typeMatched)
|
|
|
|
return .Err(.InvalidTargetType); // "Invalid target type");
|
|
|
|
}
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
Type fieldType = Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
2019-11-29 09:24:13 -08:00
|
|
|
void* fieldDataAddr = ((uint8*)(void*)obj) + mFieldData.mDataOffset + dataOffsetAdjust;
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
Type rawValueType = value.[Friend]RawGetType();
|
|
|
|
void* valueDataAddr = ((uint8*)(void*)value) + rawValueType.[Friend]mMemberDataOffset;
|
2019-11-29 09:24:13 -08:00
|
|
|
|
|
|
|
Type valueType = value.GetType();
|
|
|
|
|
|
|
|
if ((valueType != fieldType) && (valueType.IsTypedPrimitive))
|
|
|
|
valueType = valueType.UnderlyingType;
|
|
|
|
|
|
|
|
if (valueType == fieldType)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
Internal.MemCpy(fieldDataAddr, valueDataAddr, fieldType.[Friend]mSize);
|
2019-11-29 09:24:13 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return .Err(.InvalidValueType);
|
|
|
|
}
|
2019-08-23 11:56:54 -07:00
|
|
|
|
2019-11-29 09:24:13 -08:00
|
|
|
/*switch (fieldType.mTypeCode)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
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);
|
2019-11-29 09:24:13 -08:00
|
|
|
}*/
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<void> SetValue(Object obj, Variant value)
|
|
|
|
{
|
|
|
|
int32 dataOffsetAdjust = 0;
|
|
|
|
if (mTypeInstance.IsStruct)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
Type boxedType = obj.[Friend]RawGetType();
|
2019-08-23 11:56:54 -07:00
|
|
|
bool typeMatched = false;
|
|
|
|
if (boxedType.IsBoxed)
|
|
|
|
{
|
|
|
|
if (mTypeInstance == boxedType.UnderlyingType)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
dataOffsetAdjust = boxedType.[Friend]mMemberDataOffset;
|
2019-08-23 11:56:54 -07:00
|
|
|
typeMatched = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!typeMatched)
|
|
|
|
return .Err;//("Invalid target type");
|
|
|
|
}
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
Type fieldType = Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
void* dataAddr = ((uint8*)(void*)obj) + mFieldData.mDataOffset + dataOffsetAdjust;
|
|
|
|
|
|
|
|
if (value.VariantType != fieldType)
|
|
|
|
return .Err;//("Invalid type");
|
|
|
|
|
|
|
|
value.CopyValueData(dataAddr);
|
|
|
|
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static mixin Decode<T2>(void* data)
|
|
|
|
{
|
|
|
|
*((*(T2**)&data)++)
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<T> GetCustomAttribute<T>() where T : Attribute
|
|
|
|
{
|
|
|
|
if (mFieldData.mCustomAttributesIdx == -1)
|
|
|
|
return .Err;
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
void* data = mTypeInstance.[Friend]mCustomAttrDataPtr[mFieldData.mCustomAttributesIdx];
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
T attrInst = ?;
|
|
|
|
switch (AttributeInfo.GetCustomAttribute(data, typeof(T), &attrInst))
|
|
|
|
{
|
|
|
|
case .Ok: return .Ok(attrInst);
|
|
|
|
default:
|
|
|
|
return .Err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void* GetDataPtrAndType(Object value, out Type type)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
type = value.[Friend]RawGetType();
|
2019-08-23 11:56:54 -07:00
|
|
|
/*if (type.IsStruct)
|
|
|
|
return &value;*/
|
|
|
|
|
|
|
|
if (type.IsBoxed)
|
2020-03-09 06:34:16 -07:00
|
|
|
return ((uint8*)(void*)value) + type.[Friend]mMemberDataOffset;
|
2019-08-23 11:56:54 -07:00
|
|
|
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);
|
2019-11-29 09:24:13 -08:00
|
|
|
|
2019-08-23 11:56:54 -07:00
|
|
|
Type tMember = typeof(TMember);
|
|
|
|
|
|
|
|
targetDataAddr = (uint8*)targetDataAddr + mFieldData.mDataOffset;
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
Type fieldType = Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
2019-08-23 11:56:54 -07:00
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
if (tMember.[Friend]mTypeCode == TypeCode.Object)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
if (!tTarget.IsSubtypeOf(mTypeInstance))
|
|
|
|
Runtime.FatalError();
|
|
|
|
value = *(TMember*)targetDataAddr;
|
|
|
|
}
|
2020-03-09 06:34:16 -07:00
|
|
|
else if (fieldType.[Friend]mTypeCode == tMember.[Friend]mTypeCode)
|
2019-11-29 09:24:13 -08:00
|
|
|
{
|
|
|
|
Internal.MemCpy(&value, targetDataAddr, tMember.Size);
|
|
|
|
}
|
2019-08-23 11:56:54 -07:00
|
|
|
else
|
|
|
|
{
|
2019-11-29 09:24:13 -08:00
|
|
|
return .Err;
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return .Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<Variant> GetValue(Object target)
|
|
|
|
{
|
|
|
|
Variant value = Variant();
|
|
|
|
|
|
|
|
Type tTarget;
|
|
|
|
void* targetDataAddr = GetDataPtrAndType(target, out tTarget);
|
|
|
|
|
|
|
|
if (!tTarget.IsSubtypeOf(mTypeInstance))
|
|
|
|
Runtime.FatalError("Invalid type");
|
|
|
|
|
|
|
|
targetDataAddr = (uint8*)targetDataAddr + mFieldData.mDataOffset;
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
Type fieldType = Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
2019-08-23 11:56:54 -07:00
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
TypeCode typeCode = fieldType.[Friend]mTypeCode;
|
2019-08-23 11:56:54 -07:00
|
|
|
if (typeCode == TypeCode.Enum)
|
2020-03-09 06:34:16 -07:00
|
|
|
typeCode = fieldType.UnderlyingType.[Friend]mTypeCode;
|
2019-08-23 11:56:54 -07:00
|
|
|
|
2019-11-29 09:24:13 -08:00
|
|
|
if (typeCode == TypeCode.Object)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
value.[Friend]mStructType = 0;
|
|
|
|
value.[Friend]mData = *(int*)targetDataAddr;
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = Variant.Create(fieldType, targetDataAddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
Type fieldType = Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
|
|
|
value.[Friend]mStructType = (int)(void*)fieldType;
|
2019-08-23 11:56:54 -07:00
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
TypeCode typeCode = fieldType.[Friend]mTypeCode;
|
2019-08-23 11:56:54 -07:00
|
|
|
if (typeCode == TypeCode.Enum)
|
2020-03-09 06:34:16 -07:00
|
|
|
typeCode = fieldType.UnderlyingType.[Friend]mTypeCode;
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
if (typeCode == TypeCode.Int32)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
*(int32*)&value.[Friend]mData = *(int32*)targetDataAddr;
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
else if (typeCode == TypeCode.Object)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
value.[Friend]mStructType = 0;
|
|
|
|
value.[Friend]mData = (int)targetDataAddr;
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return .Err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
public struct Enumerator : IEnumerator<FieldInfo>
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
BindingFlags mBindingFlags;
|
|
|
|
TypeInstance mTypeInstance;
|
|
|
|
int32 mIdx;
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
public this(TypeInstance typeInst, BindingFlags bindingFlags)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
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++;
|
2020-03-09 06:34:16 -07:00
|
|
|
if (mIdx == mTypeInstance.[Friend]mFieldDataCount)
|
2019-08-23 11:56:54 -07:00
|
|
|
return false;
|
2020-03-09 06:34:16 -07:00
|
|
|
var fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx];
|
2019-08-23 11:56:54 -07:00
|
|
|
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
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
var fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx];
|
2019-08-23 11:56:54 -07:00
|
|
|
return FieldInfo(mTypeInstance, fieldData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Result<FieldInfo> GetNext() mut
|
|
|
|
{
|
|
|
|
if (!MoveNext())
|
|
|
|
return .Err;
|
|
|
|
return Current;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|