diff --git a/c/ffi/_demo/_wrap/wrap.c b/c/ffi/_demo/_wrap/wrap.c new file mode 100644 index 00000000..07f31c0a --- /dev/null +++ b/c/ffi/_demo/_wrap/wrap.c @@ -0,0 +1,25 @@ +#include + +struct array +{ + int x; + int y; + int z; + int k; +}; + +int demo1(struct array a) +{ + printf("c.demo1: %d %d %d %d\n",a.x,a.y,a.z,a.k); + return a.x+a.y+a.z+a.k; +} + +int demo2( int (*fn)(struct array)) { + printf("c.demo2: %p\n",fn); + struct array a; + a.x = 1; + a.y = 2; + a.z = 3; + a.k = 4; + return (*fn)(a); +} diff --git a/c/ffi/_demo/cfunc/main.go b/c/ffi/_demo/cfunc/main.go new file mode 100644 index 00000000..59f5f118 --- /dev/null +++ b/c/ffi/_demo/cfunc/main.go @@ -0,0 +1,65 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +const ( + LLGoPackage = "link" + LLGoFiles = "../_wrap/wrap.c" +) + +//llgo:type C +type Callback func(array) c.Int + +//go:linkname demo1 C.demo1 +func demo1(array) c.Int + +//go:linkname demo2 C.demo2 +func demo2(fn Callback) c.Int + +//llgo:type C +type array struct { + x c.Int + y c.Int + z c.Int + k c.Int +} + +var ( + typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil} + typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil} +) + +func main() { + cdemo1() + cdemo2() +} + +func cdemo1() { + var cif ffi.Cif + tarray := &ffi.Type{0, 0, ffi.Struct, &[]*ffi.Type{typeInt32, typeInt32, typeInt32, typeInt32, nil}[0]} + status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{tarray}[0]) + if status != ffi.OK { + panic(status) + } + ar := array{1, 2, 3, 4} + var ret int32 + ffi.Call(&cif, c.Func(demo1), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&ar)}[0]) + c.Printf(c.Str("ret: %d\n"), ret) +} + +func cdemo2() { + var cif ffi.Cif + status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0]) + if status != ffi.OK { + panic(status) + } + var ret int32 + fn := c.Func(demo1) + ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fn)}[0]) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/c/ffi/_demo/closure/main.go b/c/ffi/_demo/closure/main.go new file mode 100644 index 00000000..a85d0836 --- /dev/null +++ b/c/ffi/_demo/closure/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +const ( + LLGoPackage = "link" + LLGoFiles = "../_wrap/wrap.c" +) + +//llgo:type C +type Callback func(array) c.Int + +//go:linkname demo1 C.demo1 +func demo1(array) c.Int + +//go:linkname demo2 C.demo2 +func demo2(fn Callback) c.Int + +//llgo:type C +type array struct { + x c.Int + y c.Int + z c.Int + k c.Int +} + +func demo(a array) c.Int { + c.Printf(c.Str("go.demo %d %d %d %d\n"), a.x, a.y, a.z, a.k) + return a.x + a.y + a.z + a.k +} + +var ( + typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil} + typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil} +) + +func main() { + gofn() + c.Printf(c.Str("\n")) + goclosure() +} + +func gofn() { + var cif ffi.Cif + status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0]) + if status != ffi.OK { + panic(status) + } + var fncode unsafe.Pointer + closure := ffi.ClosureAlloc(&fncode) + defer ffi.ClosureFree(closure) + status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + ar := *(*array)(ffi.Index(args, 0)) + *(*c.Int)(ret) = demo(ar) + }, nil, fncode) + if status != ffi.OK { + panic(status) + } + var ret int32 + ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0]) + c.Printf(c.Str("ret: %d\n"), ret) +} + +func goclosure() { + var cif ffi.Cif + status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0]) + if status != ffi.OK { + panic(status) + } + fn := func(ar array) c.Int { + c.Printf(c.Str("call closure %d\n"), cif.NArgs) + return demo(ar) + } + var fncode unsafe.Pointer + closure := ffi.ClosureAlloc(&fncode) + defer ffi.ClosureFree(closure) + status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + ar := *(*array)(ffi.Index(args, 0)) + fn := *(*func(array) c.Int)(userdata) + *(*c.Int)(ret) = fn(ar) + }, unsafe.Pointer(&fn), fncode) + if status != ffi.OK { + panic(status) + } + var ret int32 + ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0]) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/c/ffi/_demo/printf/main.go b/c/ffi/_demo/printf/main.go new file mode 100644 index 00000000..cac40edd --- /dev/null +++ b/c/ffi/_demo/printf/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +var ( + typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil} + typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil} +) + +func main() { + var cif ffi.Cif + status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, 1, 2, typeInt32, &[]*ffi.Type{typePointer, typeInt32}[0]) + if status != ffi.OK { + panic(status) + } + var ret int32 + text := c.Str("hello world: %d\n") + var n int32 = 100 + ffi.Call(&cif, c.Func(c.Printf), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&text), unsafe.Pointer(&n)}[0]) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/c/ffi/_wrap/libffi.c b/c/ffi/_wrap/libffi.c new file mode 100644 index 00000000..53fa1c70 --- /dev/null +++ b/c/ffi/_wrap/libffi.c @@ -0,0 +1,5 @@ +#include + +void *llog_ffi_closure_alloc(void **code) { + return ffi_closure_alloc(sizeof(ffi_closure), code); +} diff --git a/c/ffi/abi.go b/c/ffi/abi.go new file mode 100644 index 00000000..a693166e --- /dev/null +++ b/c/ffi/abi.go @@ -0,0 +1,7 @@ +//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64)) + +package ffi + +const ( + DefaultAbi = 1 +) diff --git a/c/ffi/abi_amd64.go b/c/ffi/abi_amd64.go new file mode 100644 index 00000000..89078adb --- /dev/null +++ b/c/ffi/abi_amd64.go @@ -0,0 +1,7 @@ +//go:build freebsd || linux || darwin + +package ffi + +const ( + DefaultAbi = 2 +) diff --git a/c/ffi/ffi.go b/c/ffi/ffi.go new file mode 100644 index 00000000..f060d786 --- /dev/null +++ b/c/ffi/ffi.go @@ -0,0 +1,132 @@ +package ffi + +import ( + "unsafe" + + "github.com/goplus/llgo/c" +) + +const ( + LLGoPackage = "link: $(pkg-config --libs libffi); -lffi" + LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c" +) + +const ( + Void = iota + Int + Float + Double + LongDouble + Uint8 + Sint8 + Uint16 + Sint16 + Uint32 + Sint32 + Uint64 + Sint64 + Struct + Pointer + Complex +) + +const ( + OK = iota + BAD_TYPEDEF + BAD_ABI + BAD_ARGTYPE +) + +type Type struct { + Size uintptr + Alignment uint16 + Type uint16 + Elements **Type +} + +/*typedef struct { + ffi_abi abi; + unsigned nargs; + ffi_type **arg_types; + ffi_type *rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; +*/ + +type Cif struct { + Abi c.Uint + NArgs c.Uint + ArgTypes **Type + RType *Type + Bytes c.Uint + Flags c.Uint + //Extra c.Uint +} + +/* +ffi_status +ffi_prep_cif(ffi_cif *cif, + ffi_abi abi, + unsigned int nargs, + ffi_type *rtype, + ffi_type **atypes); +*/ +//go:linkname PrepCif C.ffi_prep_cif +func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint + +/* +ffi_status ffi_prep_cif_var(ffi_cif *cif, + ffi_abi abi, + unsigned int nfixedargs, + unsigned int ntotalargs, + ffi_type *rtype, + ffi_type **atypes); +*/ +//go:linkname PrepCifVar C.ffi_prep_cif_var +func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint + +/* +void ffi_call(ffi_cif *cif, + void (*fn)(void), + void *rvalue, + void **avalue); +*/ +//go:linkname Call C.ffi_call +func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer) + +// void *ffi_closure_alloc (size_t size, void **code); +// +//go:linkname ClosureAlloc C.llog_ffi_closure_alloc +func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer + +// void ffi_closure_free (void *); +// +//go:linkname ClosureFree C.ffi_closure_free +func ClosureFree(unsafe.Pointer) + +/* +ffi_status +ffi_prep_closure_loc (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc); +*/ + +//llgo:type C +type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) + +//go:linkname PreClosureLoc C.ffi_prep_closure_loc +func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint + +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)))) +} diff --git a/x/ffi/_demo/_wrap/wrap.c b/x/ffi/_demo/_wrap/wrap.c new file mode 100644 index 00000000..07f31c0a --- /dev/null +++ b/x/ffi/_demo/_wrap/wrap.c @@ -0,0 +1,25 @@ +#include + +struct array +{ + int x; + int y; + int z; + int k; +}; + +int demo1(struct array a) +{ + printf("c.demo1: %d %d %d %d\n",a.x,a.y,a.z,a.k); + return a.x+a.y+a.z+a.k; +} + +int demo2( int (*fn)(struct array)) { + printf("c.demo2: %p\n",fn); + struct array a; + a.x = 1; + a.y = 2; + a.z = 3; + a.k = 4; + return (*fn)(a); +} diff --git a/x/ffi/_demo/cfunc/main.go b/x/ffi/_demo/cfunc/main.go new file mode 100644 index 00000000..f2111dce --- /dev/null +++ b/x/ffi/_demo/cfunc/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/x/ffi" +) + +const ( + LLGoPackage = "link" + LLGoFiles = "../_wrap/wrap.c" +) + +//llgo:type C +type Callback func(array) c.Int + +//go:linkname demo1 C.demo1 +func demo1(array) c.Int + +//go:linkname demo2 C.demo2 +func demo2(fn Callback) c.Int + +//llgo:type C +type array struct { + x c.Int + y c.Int + z c.Int + k c.Int +} + +func main() { + cdemo1() + cdemo2() +} + +func cdemo1() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.StructOf(ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32)) + if err != nil { + panic(err) + } + ar := array{1, 2, 3, 4} + var ret int32 + ffi.Call(sig, c.Func(demo1), unsafe.Pointer(&ret), unsafe.Pointer(&ar)) + c.Printf(c.Str("ret: %d\n"), ret) +} + +func cdemo2() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + var ret int32 + fn := c.Func(demo1) + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/x/ffi/_demo/closure/main.go b/x/ffi/_demo/closure/main.go new file mode 100644 index 00000000..f50f1879 --- /dev/null +++ b/x/ffi/_demo/closure/main.go @@ -0,0 +1,78 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/x/ffi" +) + +const ( + LLGoPackage = "link" + LLGoFiles = "../_wrap/wrap.c" +) + +//llgo:type C +type Callback func(array) c.Int + +//go:linkname demo1 C.demo1 +func demo1(array) c.Int + +//go:linkname demo2 C.demo2 +func demo2(fn Callback) c.Int + +//llgo:type C +type array struct { + x c.Int + y c.Int + z c.Int + k c.Int +} + +func demo(a array) c.Int { + c.Printf(c.Str("go.demo %d %d %d %d\n"), a.x, a.y, a.z, a.k) + return a.x + a.y + a.z + a.k +} + +func main() { + gofn() + c.Printf(c.Str("\n")) + goclosure() +} + +func gofn() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + closure := ffi.NewClosure() + defer closure.Free() + err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + ar := *(*array)(ffi.Index(args, 0)) + *(*c.Int)(ret) = demo(ar) + }, nil) + var ret int32 + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} + +func goclosure() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + fn := func(ar array) c.Int { + c.Printf(c.Str("call closure %d\n"), sig.NArgs) + return demo(ar) + } + closure := ffi.NewClosure() + defer closure.Free() + err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + ar := *(*array)(ffi.Index(args, 0)) + fn := *(*func(array) c.Int)(userdata) + *(*c.Int)(ret) = fn(ar) + }, unsafe.Pointer(&fn)) + var ret int32 + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/x/ffi/_demo/gofunc/main.go b/x/ffi/_demo/gofunc/main.go new file mode 100644 index 00000000..b6bb486e --- /dev/null +++ b/x/ffi/_demo/gofunc/main.go @@ -0,0 +1,62 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/x/ffi" +) + +type array struct { + x int + y int + z int + k int +} + +type Func func(ar array, i interface{}, s string, slice []int) (int, float64) + +func demo(p1 array, p2 interface{}, p3 string, p4 []int) (int, float64) { + println(p1.x, p1.y, p1.z, p1.k) + println(p2) + println(p3) + println(p4) + for _, v := range p4 { + println(v) + } + return 200, 3.14 +} + +func main() { + sig, err := ffi.NewSignature(ffi.StructOf(ffi.TypeInt, ffi.TypeFloat64), + ffi.StructOf(ffi.TypeInt, ffi.TypeInt, ffi.TypeInt, ffi.TypeInt), + ffi.TypeInterface, ffi.TypeString, ffi.TypeSlice) + if err != nil { + panic(err) + } + fn := demo + closure := ffi.NewClosure() + defer closure.Free() + err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + p1 := *(*array)(ffi.Index(args, 0)) + p2 := *(*any)(ffi.Index(args, 1)) + p3 := *(*string)(ffi.Index(args, 2)) + p4 := *(*[]int)(ffi.Index(args, 3)) + fn := *(*Func)(userdata) + p := (*struct { + i int + f float64 + })(ret) + p.i, p.f = fn(p1, p2, p3, p4) + }, unsafe.Pointer(&fn)) + var ret struct { + i int + f float64 + } + p1 := array{1, 2, 3, 4} + var p2 any = 100 + p3 := "hello world" + p4 := []int{100, 200, 300} + ffi.Call(sig, closure.Fn, unsafe.Pointer(&ret), + unsafe.Pointer(&p1), unsafe.Pointer(&p2), unsafe.Pointer(&p3), unsafe.Pointer(&p4)) + println("ret:", ret.i, ret.f) +} diff --git a/x/ffi/_demo/printf/main.go b/x/ffi/_demo/printf/main.go new file mode 100644 index 00000000..6fca035e --- /dev/null +++ b/x/ffi/_demo/printf/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/x/ffi" +) + +func main() { + sig, err := ffi.NewSignatureVar(ffi.TypeInt32, 1, ffi.TypePointer, ffi.TypeInt32) + if err != nil { + panic(err) + } + var ret int32 + text := c.Str("hello world: %d\n") + var n int32 = 100 + ffi.Call(sig, c.Func(c.Printf), unsafe.Pointer(&ret), unsafe.Pointer(&text), unsafe.Pointer(&n)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/x/ffi/ffi.go b/x/ffi/ffi.go new file mode 100644 index 00000000..f07a6574 --- /dev/null +++ b/x/ffi/ffi.go @@ -0,0 +1,93 @@ +package ffi + +import ( + "fmt" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +type Type = ffi.Type + +type Signature = ffi.Cif + +type Error int + +func (s Error) Error() string { + switch s { + case ffi.OK: + return "ok" + case ffi.BAD_TYPEDEF: + return "bad type def" + case ffi.BAD_ABI: + return "bad ABI" + case ffi.BAD_ARGTYPE: + return "bad argument type" + } + return fmt.Sprintf("invalid status: %v", int(s)) +} + +func NewSignature(ret *Type, args ...*Type) (*Signature, error) { + var cif Signature + var atype **Type + if len(args) > 0 { + atype = &args[0] + } + status := ffi.PrepCif(&cif, ffi.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 Signature + var atype **Type + if len(args) > 0 { + atype = &args[0] + } + status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, c.Uint(fixed), c.Uint(len(args)), ret, atype) + if status == ffi.OK { + 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 == ffi.OK { + return nil + } + return Error(status) +} + +func Index(args *unsafe.Pointer, i uintptr) unsafe.Pointer { + return ffi.Index(args, i) +} diff --git a/x/ffi/type.go b/x/ffi/type.go new file mode 100644 index 00000000..e43a806c --- /dev/null +++ b/x/ffi/type.go @@ -0,0 +1,124 @@ +package ffi + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +type BasicKind int + +const ( + Void BasicKind = iota // type is invalid + + // predeclared types + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + String + UnsafePointer + Interface + Slice + + // aliases + Byte = Uint8 + Rune = Int32 +) + +const ( + _64bit = 1 << (^uintptr(0) >> 63) / 2 + _Int = _64bit*ffi.Sint64 + (1-_64bit)*ffi.Sint32 + _Uint = _64bit*ffi.Uint64 + (1-_64bit)*ffi.Uint32 + _sizei = unsafe.Sizeof(0) + _aligni = uint16(unsafe.Alignof(0)) + _sizeci = unsafe.Sizeof(c.Int(0)) + _alignci = uint16(unsafe.Alignof(c.Int(0))) + _sizes = unsafe.Sizeof("") + _aligns = uint16(unsafe.Alignof("")) +) + +var ( + TypeVoid = &Type{1, 1, ffi.Void, nil} + TypeBool = &Type{1, 1, ffi.Uint8, nil} + TypeInt8 = &Type{1, 1, ffi.Sint8, nil} + TypeInt16 = &Type{2, 2, ffi.Sint16, nil} + TypeInt32 = &Type{4, 4, ffi.Sint32, nil} + TypeInt64 = &Type{8, 8, ffi.Sint64, nil} + TypeUint8 = &Type{1, 1, ffi.Uint8, nil} + TypeUint16 = &Type{2, 2, ffi.Uint16, nil} + TypeUint32 = &Type{4, 4, ffi.Uint32, nil} + TypeUint64 = &Type{8, 8, ffi.Uint64, nil} + TypeFloat32 = &Type{4, 4, ffi.Float, nil} + TypeFloat64 = &Type{8, 8, ffi.Double, nil} + TypeComplex64 = &Type{8, 4, ffi.Complex, &[]*Type{TypeFloat32, nil}[0]} + TypeComplex128 = &Type{16, 8, ffi.Complex, &[]*Type{TypeFloat64, nil}[0]} + TypeInt = &Type{_sizei, _aligni, _Int, nil} + TypeUint = &Type{_sizei, _aligni, _Uint, nil} + TypeUintptr = &Type{_sizei, _aligni, _Uint, nil} + TypePointer = &Type{_sizei, _aligni, ffi.Pointer, nil} + TypeString = StructOf(TypePointer, TypeInt) + TypeInterface = StructOf(TypePointer, TypePointer) + TypeSlice = StructOf(TypePointer, TypeInt, TypeInt) +) + +var Typ = []*Type{ + Void: TypeVoid, + Bool: TypeBool, + Int: TypeInt, + Int8: TypeInt8, + Int16: TypeInt16, + Int32: TypeInt32, + Int64: TypeInt64, + Uint: TypeUint, + Uint8: TypeUint8, + Uint16: TypeUint16, + Uint32: TypeUint32, + Uint64: TypeUint64, + Uintptr: TypeUintptr, + Float32: TypeFloat32, + Float64: TypeFloat64, + Complex64: TypeComplex64, + Complex128: TypeComplex128, + String: TypeString, + UnsafePointer: TypePointer, + Interface: TypeInterface, + Slice: TypeSlice, +} + +func ArrayOf(elem *Type, N int) *Type { + fs := make([]*Type, N+1) + for i := 0; i < N; i++ { + fs[i] = elem + } + return &Type{ + 0, + 0, + ffi.Struct, + &fs[0], + } +} + +func StructOf(fields ...*Type) *Type { + fs := make([]*Type, len(fields)+1) + copy(fs, fields) + return &Type{ + 0, + 0, + ffi.Struct, + &fs[0], + } +}