Files
llgo/c/ffi/ffi.go
2024-10-23 10:53:18 +08:00

107 lines
2.0 KiB
Go

package ffi
import (
"fmt"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/ffi/ffi"
)
type Type = ffi.Type
type Signature = ffi.Cif
type Abi c.Uint
type Error c.Uint
const (
OK Error = iota
BAD_TYPEDEF
BAD_ABI
BAD_ARGTYPE
)
func (s Error) Error() string {
switch s {
case OK:
return "ok"
case BAD_TYPEDEF:
return "bad type def"
case BAD_ABI:
return "bad ABI"
case BAD_ARGTYPE:
return "bad argument type"
}
return fmt.Sprintf("invalid status: %v", int(s))
}
func NewSignature(ret *Type, args ...*Type) (*Signature, error) {
var cif ffi.Cif
var atype **Type
if len(args) > 0 {
atype = &args[0]
}
status := ffi.PrepCif(&cif, c.Uint(DefaultAbi), c.Uint(len(args)), ret, atype)
if status == 0 {
return &cif, nil
}
return nil, Error(status)
}
func NewSignatureVar(ret *Type, fixed int, args ...*Type) (*Signature, error) {
var cif ffi.Cif
var atype **Type
if len(args) > 0 {
atype = &args[0]
}
status := ffi.PrepCifVar(&cif, c.Uint(DefaultAbi), c.Uint(fixed), c.Uint(len(args)), ret, atype)
if status == 0 {
return &cif, nil
}
return nil, Error(status)
}
func Call(cif *Signature, fn unsafe.Pointer, ret unsafe.Pointer, args ...unsafe.Pointer) {
var avalues *unsafe.Pointer
if len(args) > 0 {
avalues = &args[0]
}
ffi.Call(cif, fn, ret, avalues)
}
type Closure struct {
ptr unsafe.Pointer
Fn unsafe.Pointer
}
func NewClosure() *Closure {
c := &Closure{}
c.ptr = ffi.ClosureAlloc(&c.Fn)
return c
}
func (c *Closure) Free() {
if c != nil && c.ptr != nil {
ffi.ClosureFree(c.ptr)
c.ptr = nil
}
}
func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Pointer) error {
status := ffi.PreClosureLoc(c.ptr, cif, fn, userdata, c.Fn)
if status == 0 {
return nil
}
return Error(status)
}
func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(ptr) + offset)
}
func Index(args *unsafe.Pointer, i uintptr) unsafe.Pointer {
return (*(*unsafe.Pointer)(add(unsafe.Pointer(args), i*unsafe.Sizeof(0))))
}