2019-08-23 11:56:54 -07:00
|
|
|
namespace System.Reflection
|
|
|
|
{
|
|
|
|
static class Convert
|
|
|
|
{
|
|
|
|
static (Type type, void* ptr) GetTypeAndPointer(Object obj)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
var objType = obj.[Friend]RawGetType();
|
|
|
|
void* dataPtr = (uint8*)Internal.UnsafeCastToPtr(obj) + objType.[Friend]mMemberDataOffset;
|
2019-08-23 11:56:54 -07:00
|
|
|
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);
|
2020-03-09 06:34:16 -07:00
|
|
|
switch (objType.[Friend]mTypeCode)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-22 17:06:26 -07:00
|
|
|
public static Result<int64> ToInt64(Variant variant)
|
|
|
|
{
|
|
|
|
var variant;
|
|
|
|
var dataPtr = variant.DataPtr;
|
|
|
|
switch (variant.VariantType.[Friend]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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-23 11:56:54 -07:00
|
|
|
public static bool IntCanFit(int64 val, Type type)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
switch (type.[Friend]mTypeCode)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
case .Int8: return (val >= -0x80) && (val <= 0x7F);
|
|
|
|
case .Int16: return (val >= -0x8000) && (val <= 0x7FFF);
|
|
|
|
case .Int32: return (val >= -0x80000000) && (val <= 0x7FFF'FFFF);
|
2019-10-05 10:26:26 -07:00
|
|
|
case .Int64: return true;
|
2019-08-23 11:56:54 -07:00
|
|
|
case .UInt8, .Char8: return (val >= 0) && (val <= 0xFF);
|
|
|
|
case .UInt16, .Char16: return (val >= 0) && (val <= 0xFFFF);
|
|
|
|
case .UInt32, .Char32: return (val >= 0) && (val <= 0xFFFFFFFF);
|
2019-10-05 10:26:26 -07:00
|
|
|
case .UInt64: return (val >= 0);
|
2019-08-23 11:56:54 -07:00
|
|
|
#if BF_64_BIT
|
2019-10-05 10:26:26 -07:00
|
|
|
case .Int: return true;
|
|
|
|
case .UInt: return (val >= 0);
|
2019-08-23 11:56:54 -07:00
|
|
|
#else
|
|
|
|
case .Int: return (val >= -0x80000000) && (val <= 0x7FFF'FFFF);
|
|
|
|
case .UInt: return (val >= 0) && (val <= 0xFFFFFFFF);
|
|
|
|
#endif
|
|
|
|
default: return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-22 17:06:26 -07:00
|
|
|
public static Result<Variant> ConvertTo(Variant variant, Type type)
|
|
|
|
{
|
|
|
|
var variant;
|
|
|
|
|
|
|
|
if (variant.VariantType == type)
|
|
|
|
{
|
|
|
|
return Variant.CreateFromVariant(variant);
|
|
|
|
}
|
|
|
|
|
|
|
|
var varType = variant.VariantType;
|
|
|
|
void* dataPtr = variant.DataPtr;
|
|
|
|
|
|
|
|
if (varType.IsPrimitive)
|
|
|
|
{
|
|
|
|
if (varType.IsInteger)
|
|
|
|
{
|
|
|
|
int64 intVal = ToInt64(variant);
|
|
|
|
switch (type.[Friend]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 (varType.IsFloatingPoint)
|
|
|
|
{
|
|
|
|
if ((type.[Friend]mTypeCode == .Double) &&
|
|
|
|
(varType.[Friend]mTypeCode == .Float))
|
|
|
|
{
|
|
|
|
double val = (.)*(float*)dataPtr;
|
|
|
|
return Variant.Create(type, &val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return .Err;
|
|
|
|
}
|
|
|
|
|
2019-08-23 11:56:54 -07:00
|
|
|
public static Result<Variant> ConvertTo(Object obj, Type type)
|
|
|
|
{
|
|
|
|
if (obj.GetType() == type)
|
|
|
|
{
|
|
|
|
return Variant.Create(obj, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
var (objType, dataPtr) = GetTypeAndPointer(obj);
|
2020-06-22 17:06:26 -07:00
|
|
|
|
2019-08-23 11:56:54 -07:00
|
|
|
if (objType.IsPrimitive)
|
|
|
|
{
|
|
|
|
if (objType.IsInteger)
|
|
|
|
{
|
|
|
|
int64 intVal = ToInt64(obj);
|
2020-03-09 06:34:16 -07:00
|
|
|
switch (type.[Friend]mTypeCode)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2020-03-09 06:34:16 -07:00
|
|
|
if ((type.[Friend]mTypeCode == .Double) &&
|
|
|
|
(objType.[Friend]mTypeCode == .Float))
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
double val = (.)*(float*)dataPtr;
|
|
|
|
return Variant.Create(type, &val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return .Err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|