genbindings/connect: initial implementation

This commit is contained in:
mappu 2024-08-18 17:48:17 +12:00
parent c8ac62fccd
commit f488e54f8b
3 changed files with 100 additions and 2 deletions

View File

@ -68,6 +68,49 @@ func emitReturnTypeCabi(p CppParameter) string {
}
}
// emitParametersCpp emits the parameter definitions exactly how Qt C++ defines them.
func emitParametersCpp(m CppMethod) string {
tmp := make([]string, 0, len(m.Parameters))
for _, p := range m.Parameters {
cppType := p.ParameterType
if p.Const {
cppType = "const " + cppType
}
if p.Pointer {
cppType += "*"
}
if p.ByRef {
cppType += "&"
}
tmp = append(tmp, cppType+" "+p.ParameterName)
}
return strings.Join(tmp, `, `)
}
func emitParameterTypesCpp(m CppMethod) string {
tmp := make([]string, 0, len(m.Parameters))
for _, p := range m.Parameters {
cppType := p.ParameterType
if p.Const {
cppType = "const " + cppType
}
if p.Pointer {
cppType += "*"
}
if p.ByRef {
cppType += "&"
}
tmp = append(tmp, cppType)
}
return strings.Join(tmp, `, `)
}
func emitParametersCabi(m CppMethod, selfType string) string {
tmp := make([]string, 0, len(m.Parameters)+1)
@ -342,6 +385,10 @@ extern "C" {
for _, m := range c.Methods {
ret.WriteString(fmt.Sprintf("%s %s_%s(%s);\n", emitReturnTypeCabi(m.ReturnType), c.ClassName, m.SafeMethodName(), emitParametersCabi(m, c.ClassName+"*")))
if m.IsSignal {
ret.WriteString(fmt.Sprintf("%s %s_connect_%s(void* slot);\n", emitReturnTypeCabi(m.ReturnType), c.ClassName, m.SafeMethodName()))
}
}
// delete
@ -383,7 +430,13 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
ret.WriteString(`#include <` + ref + ">\n")
}
ret.WriteString("\n")
ret.WriteString(`
extern "C" {
extern void miqt_exec_callback(void* cb, int argc, void* argv);
}
`)
for _, c := range src.Classes {
@ -496,6 +549,19 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) {
shouldReturn, callTarget, nativeMethodName, forwarding,
afterCall,
))
if m.IsSignal {
exactSignal := `static_cast<void (` + c.ClassName + `::*)(` + emitParameterTypesCpp(m) + `)>(&` + c.ClassName + `::` + nativeMethodName + `)`
ret.WriteString(
`void ` + c.ClassName + `_connect_` + m.SafeMethodName() + `(` + c.ClassName + `* self, void* slot) {` + "\n" +
"\t" + c.ClassName + `::connect(self, ` + exactSignal + `, self, [=](` + emitParametersCpp(m) + `) {` + "\n" +
"\t\t" + `miqt_exec_callback(slot, 0, nullptr);` + "\n" +
"\t});\n" +
"}\n" +
"\n",
)
}
}
// Delete

View File

@ -230,7 +230,7 @@ func emitParametersGo2CABIForwarding(m CppMethod) (preamble string, fowarding st
func emitGo(src *CppParsedHeader, headerName string) (string, error) {
ret := strings.Builder{}
ret.WriteString(`package miqt
ret.WriteString(`package qt
/*
@ -374,6 +374,20 @@ import "C"
` + afterword + `}
`)
// Add Connect() wrappers for signal functions
if m.IsSignal {
imports["unsafe"] = struct{}{}
imports["runtime/cgo"] = struct{}{}
ret.WriteString(`func (this *` + c.ClassName + `) On` + m.SafeMethodName() + `(slot func()) {
var slotWrapper miqtCallbackFunc = func(argc C.int, args *C.void) {
slot()
}
C.` + c.ClassName + `_connect_` + m.SafeMethodName() + `(this.h, unsafe.Pointer(uintptr(cgo.NewHandle(slotWrapper))))
}
`)
}
}
if AllowDelete(c) {

18
qt/binding.go Normal file
View File

@ -0,0 +1,18 @@
package qt
// SPDX-License-Identifier: MIT
type miqtCallbackFunc func(argc C.int, args *C.void)
//export miqt_exec_callback
func miqt_exec_callback(cb *C.void, argc C.int, args *C.void) {
// Our CABI for all callbacks is void(int, void*).
// Our Go ABI is CallbackFunc
// Then the Go bindings can unmarshal the arguments and C.free() them as necessary
cfunc, ok := (cgo.Handle(uintptr(unsafe.Pointer(cb))).Value()).(miqtCallbackFunc)
if !ok {
panic("miqt: callback of non-callback type (heap corruption?)")
}
cfunc(argc, args)
}