package cgo /* #include #include typedef int (*cgo_call_int_fn0_t)(void); typedef int (*cgo_call_int_fn1_t)(uintptr_t); typedef int (*cgo_call_int_fn2_t)(uintptr_t, uintptr_t); typedef int (*cgo_call_int_fn3_t)(uintptr_t, uintptr_t, uintptr_t); int cgo_call_0(uintptr_t fn) { return ((cgo_call_int_fn0_t)fn)(); } int cgo_call_1(uintptr_t fn, uintptr_t a0) { return ((cgo_call_int_fn1_t)fn)(a0); } int cgo_call_2(uintptr_t fn, uintptr_t a0, uintptr_t a1) { return ((cgo_call_int_fn2_t)fn)(a0, a1); } int cgo_call_3(uintptr_t fn, uintptr_t a0, uintptr_t a1, uintptr_t a2) { return ((cgo_call_int_fn3_t)fn)(a0, a1, a2); } */ import "C" import ( "fmt" "strconv" "unsafe" ) // SizeT converts a Go int into a C size_t for cgo calls. // // size := cgo.SizeT(len(data)) func SizeT(value int) C.size_t { if value < 0 { panic("cgo.SizeT: negative values are not representable as C.size_t") } if value > 0 { sizeBits := int(unsafe.Sizeof(C.size_t(0)) * 8) if sizeBits < strconv.IntSize { maxSize := (uint64(1) << sizeBits) - 1 if uint64(value) > maxSize { panic("cgo.SizeT: value exceeds C.size_t range") } } } return C.size_t(value) } // Int converts a Go int into a C int for cgo calls. // // rc := cgo.Int(returnCode) func Int(value int) C.int { if value < -2147483648 || value > 2147483647 { panic("cgo.Int: value exceeds C.int range") } return C.int(value) } // Call invokes a C function pointer and maps a non-zero return into a Go error. // // err := cgo.Call(unsafe.Pointer(C.some_function), cgo.SizeT(len(data))) // err == nil indicates success. func Call(function unsafe.Pointer, args ...interface{}) error { if function == nil { panic("cgo.Call: function pointer is nil") } var result uintptr target := uintptr(function) switch len(args) { case 0: result = uintptr(C.cgo_call_0(C.uintptr_t(target))) case 1: a0, ok := toSyscallArg(args[0]) if !ok { panic("cgo.Call: unsupported argument type") } result = uintptr(C.cgo_call_1(C.uintptr_t(target), C.uintptr_t(a0))) case 2: a0, ok := toSyscallArg(args[0]) if !ok { panic("cgo.Call: unsupported argument type") } a1, ok := toSyscallArg(args[1]) if !ok { panic("cgo.Call: unsupported argument type") } result = uintptr(C.cgo_call_2(C.uintptr_t(target), C.uintptr_t(a0), C.uintptr_t(a1))) case 3: a0, ok := toSyscallArg(args[0]) if !ok { panic("cgo.Call: unsupported argument type") } a1, ok := toSyscallArg(args[1]) if !ok { panic("cgo.Call: unsupported argument type") } a2, ok := toSyscallArg(args[2]) if !ok { panic("cgo.Call: unsupported argument type") } result = uintptr(C.cgo_call_3(C.uintptr_t(target), C.uintptr_t(a0), C.uintptr_t(a1), C.uintptr_t(a2))) default: panic("cgo.Call: unsupported argument count: max 3") } if result != 0 { return fmt.Errorf("cgo.Call: return code %d", int(result)) } return nil } func toSyscallArg(value interface{}) (uintptr, bool) { switch typed := value.(type) { case nil: return 0, true case uintptr: return typed, true case unsafe.Pointer: return uintptr(typed), true case C.char: return uintptr(typed), true case C.int: return uintptr(typed), true case C.size_t: return uintptr(typed), true case *C.char: return uintptr(unsafe.Pointer(typed)), true case *byte: return uintptr(unsafe.Pointer(typed)), true case bool: if typed { return 1, true } return 0, true case int: return uintptr(typed), true case int8: return uintptr(typed), true case int16: return uintptr(typed), true case int32: return uintptr(typed), true case int64: return uintptr(typed), true case uint: return uintptr(typed), true case uint8: return uintptr(typed), true case uint16: return uintptr(typed), true case uint32: return uintptr(typed), true case uint64: return uintptr(typed), true default: return 0, false } } // GoString converts a null-terminated C string to a Go string. // // cStr := C.CString("example") // result := cgo.GoString(cStr) // cgo.Free(unsafe.Pointer(cStr)) func GoString(cs *C.char) string { if cs == nil { return "" } return C.GoString(cs) } // CString converts a Go string to a C string. // // cStr := cgo.CString("hello") // defer cgo.Free(unsafe.Pointer(cStr)) func CString(value string) *C.char { return C.CString(value) } // Free releases memory previously returned by CString. // // cStr := cgo.CString("hello") // cgo.Free(unsafe.Pointer(cStr)) func Free(ptr unsafe.Pointer) { if ptr == nil { return } C.free(ptr) }