1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 12:32:20 +02:00
Beef/BeefLibs/corlib/src/FFI/Function.bf

224 lines
4.1 KiB
Beef

namespace System.FFI
{
[CRepr]
struct FFIType
{
public enum TypeKind : uint16
{
Void,
Int,
Float,
Double,
LongDouble,
UInt8,
SInt8,
UInt16,
SInt16,
UInt32,
SInt32,
UInt64,
SInt64,
Struct,
Pointer
}
public int mSize;
public uint16 mAlignment;
public TypeKind mTypeKind;
public FFIType** mElements;
public this(int size, int align, TypeKind typeKind, FFIType** elements = null)
{
mSize = size;
mAlignment = (.)align;
mTypeKind = typeKind;
mElements = elements;
}
public this(int size, TypeKind typeKind)
{
mSize = size;
mAlignment = (uint16)size;
mTypeKind = typeKind;
mElements = null;
}
public static FFIType Void = .(1, .Void);
public static FFIType UInt8 = .(1, .UInt8);
public static FFIType Int8 = .(1, .SInt8);
public static FFIType UInt16 = .(2, .UInt16);
public static FFIType Int16 = .(2, .SInt16);
public static FFIType UInt32 = .(4, .UInt32);
public static FFIType Int32 = .(4, .SInt32);
public static FFIType UInt64 = .(8, .UInt64);
public static FFIType Int64 = .(8, .SInt64);
public static FFIType Float = .(4, .Float);
public static FFIType Double = .(8, .Double);
public static FFIType Pointer = .(sizeof(void*), .Pointer);
public static FFIType* Get(Type type, void* allocBytes = null, int* inOutSize = null)
{
var type;
if (type.IsTypedPrimitive)
type = type.UnderlyingType;
switch (type.[Friend]mTypeCode)
{
case .None:
return &FFIType.Void;
case .Boolean,
.Char8,
.UInt8:
return &FFIType.UInt8;
case .Int8:
return &FFIType.Int8;
case .Char16,
.UInt16:
return &FFIType.UInt16;
case .Int16:
return &FFIType.Int16;
case .Char32,
.UInt32:
return &FFIType.UInt32;
case .Int32:
return &FFIType.Int32;
case .UInt64:
return &FFIType.UInt64;
case .Int64:
return &FFIType.Int64;
case .Float:
return &FFIType.Float;
case .Double:
return &FFIType.Double;
case .Struct:
int wantSize = sizeof(FFIType);
if (allocBytes == null)
{
*inOutSize = wantSize;
return null;
}
FFIType* ffiType = (FFIType*)allocBytes;
ffiType.mSize = type.[Friend]mSize;
ffiType.mAlignment = type.[Friend]mAlign;
ffiType.mElements = null;
ffiType.mTypeKind = .Struct;
return ffiType;
case .Pointer,
.Interface,
.Object:
return &FFIType.Pointer;
#if BF_64_BIT
case .Int:
return &FFIType.Int64;
case .UInt:
return &FFIType.UInt64;
#else
case .Int:
return &FFIType.Int32;
case .UInt:
return &FFIType.UInt32;
#endif
default:
return null;
}
}
}
enum FFIResult : int32
{
OK,
BadTypeDef,
BadABI
}
#if BF_PLATFORM_WINDOWS
#if BF_64_BIT
[AllowDuplicates]
enum FFIABI : int32
{
NotSet = 0,
StdCall = 1,
ThisCall = 1,
FastCall = 1,
MS_CDecl = 1,
Default = 1
}
#else
[AllowDuplicates]
enum FFIABI : int32
{
NotSet = 0,
SysV,
StdCall,
ThisCall,
FastCall,
MS_CDecl,
Default = MS_CDecl
}
#endif
#else //!BF_PLATFORM_WINDOWS
#if BF_64_BIT
[AllowDuplicates]
enum FFIABI : int32
{
NotSet = 0,
SysV,
Unix64,
Default = Unix64
}
#else
[AllowDuplicates]
enum FFIABI : int32
{
NotSet = 0,
SysV,
Unix64,
Default = SysV
}
#endif
#endif
struct FFILIB
{
[CRepr]
public struct FFICIF
{
FFIABI mAbi;
uint32 mNArgs;
FFIType **mArgTypes;
FFIType *mRType;
uint32 mBytes;
uint32 mFlags;
}
public static extern void* ClosureAlloc(int size, void** outFunc);
public static extern FFIResult PrepCif(FFICIF* cif, FFIABI abi, int32 nargs, FFIType* rtype, FFIType** argTypes);
public static extern void Call(FFICIF* cif, void* funcPtr, void* rvalue, void** args);
}
struct FFICaller
{
FFILIB.FFICIF mCIF;
public Result<void, FFIResult> Prep(FFIABI abi, int32 nargs, FFIType* rtype, FFIType** argTypes) mut
{
let res = FFILIB.PrepCif(&mCIF, abi, nargs, rtype, argTypes);
if (res == .OK)
return .Ok;
return .Err(res);
}
public void Call(void* funcPtr, void* rvalue, void** args) mut
{
FFILIB.Call(&mCIF, funcPtr, rvalue, args);
}
}
}