diff --git a/cmd/genbindings/emitcabi.go b/cmd/genbindings/emitcabi.go index b4110e55..f48728bc 100644 --- a/cmd/genbindings/emitcabi.go +++ b/cmd/genbindings/emitcabi.go @@ -9,7 +9,7 @@ import ( func (p CppParameter) RenderTypeCabi() string { if p.ParameterType == "QString" { - return "struct miqt_string*" + return "struct miqt_string" } else if _, ok := p.QListOf(); ok { return "struct miqt_array*" @@ -146,7 +146,7 @@ func emitParametersCabi(m CppMethod, selfType string) string { for _, p := range m.Parameters { if p.ParameterType == "QString" { - tmp = append(tmp, "struct miqt_string* "+p.ParameterName) + tmp = append(tmp, "struct miqt_string "+p.ParameterName) } else if t, ok := p.QListOf(); ok { tmp = append(tmp, "struct miqt_array* /* of "+t.RenderTypeCabi()+" */ "+p.ParameterName) @@ -197,9 +197,10 @@ func emitCABI2CppForwarding(p CppParameter, indent string) (preamble string, for nameprefix := makeNamePrefix(p.ParameterName) if p.ParameterType == "QString" { - // The CABI has accepted two parameters - need to convert to one real QString - // Create it on the stack - preamble += indent + "QString " + nameprefix + "_QString = QString::fromUtf8(&" + p.ParameterName + "->data, " + p.ParameterName + "->len);\n" + // The CABI received parameter is a struct miqt_string, passed by value + // C++ needs it as a QString. Create one on the stack for automatic cleanup + // The caller will free the miqt_string + preamble += indent + "QString " + nameprefix + "_QString = QString::fromUtf8(" + p.ParameterName + ".data, " + p.ParameterName + ".len);\n" return preamble, nameprefix + "_QString" } else if listType, ok := p.QListOf(); ok { @@ -315,7 +316,11 @@ func emitAssignCppToCabi(assignExpression string, p CppParameter, rvalue string) afterCall += indent + "QByteArray " + namePrefix + "_b = " + namePrefix + "_ret.toUtf8();\n" } - afterCall += indent + assignExpression + "miqt_strdup(" + namePrefix + "_b.data(), " + namePrefix + "_b.length());\n" + afterCall += indent + "struct miqt_string " + namePrefix + "_ms;\n" + afterCall += indent + namePrefix + "_ms.len = " + namePrefix + "_b.length();\n" + afterCall += indent + namePrefix + "_ms.data = static_cast(malloc(" + namePrefix + "_ms.len));\n" + afterCall += indent + "memcpy(" + namePrefix + "_ms.data, " + namePrefix + "_b.data(), " + namePrefix + "_ms.len);\n" + afterCall += indent + assignExpression + namePrefix + "_ms;\n" } else if t, ok := p.QListOf(); ok { diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index 8c64ccd3..efe1a8be 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -142,7 +142,7 @@ func (p CppParameter) RenderTypeGo(gfs *goFileState) string { func (p CppParameter) parameterTypeCgo() string { if p.ParameterType == "QString" { - return "*C.struct_miqt_string" + return "C.struct_miqt_string" } if _, ok := p.QListOf(); ok { @@ -256,11 +256,13 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble // Go: convert string -> miqt_string* // CABI: convert miqt_string* -> real QString - gfs.imports["libmiqt"] = struct{}{} - preamble += nameprefix + "_ms := libmiqt.Strdupg(" + p.ParameterName + ")\n" - preamble += "defer C.free(" + nameprefix + "_ms)\n" + gfs.imports["unsafe"] = struct{}{} + preamble += nameprefix + "_ms := C.struct_miqt_string{}\n" + preamble += nameprefix + "_ms.data = C.CString(" + p.ParameterName + ")\n" + preamble += nameprefix + "_ms.len = C.size_t(len(" + p.ParameterName + "))\n" + preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_ms.data))\n" - rvalue = "(*C.struct_miqt_string)(" + nameprefix + "_ms)" + rvalue = nameprefix + "_ms" } else if listType, ok := p.QListOf(); ok { // QList @@ -359,9 +361,9 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue } else if rt.ParameterType == "QString" { gfs.imports["unsafe"] = struct{}{} - shouldReturn = "var " + namePrefix + "_ms *C.struct_miqt_string = " - afterword += namePrefix + "_ret := C.GoStringN(&" + namePrefix + "_ms.data, C.int(int64(" + namePrefix + "_ms.len)))\n" - afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ms))\n" + shouldReturn = "var " + namePrefix + "_ms C.struct_miqt_string = " + afterword += namePrefix + "_ret := C.GoStringN(" + namePrefix + "_ms.data, C.int(int64(" + namePrefix + "_ms.len)))\n" + afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ms.data))\n" afterword += assignExpr + namePrefix + "_ret" return shouldReturn + " " + rvalue + "\n" + afterword diff --git a/libmiqt/libmiqt.cpp b/libmiqt/libmiqt.cpp deleted file mode 100644 index 5b786b34..00000000 --- a/libmiqt/libmiqt.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "libmiqt.h" - -struct miqt_string* miqt_strdup(const char* src, size_t len) { - struct miqt_string* ret = (struct miqt_string*)( malloc(len + sizeof(size_t)) ); - ret->len = len; - memcpy(&ret->data, src, len); - return ret; -} diff --git a/libmiqt/libmiqt.go b/libmiqt/libmiqt.go new file mode 100644 index 00000000..791dfa1c --- /dev/null +++ b/libmiqt/libmiqt.go @@ -0,0 +1,10 @@ +package libmiqt + +// SPDX-License-Identifier: MIT + +/* + +#include "libmiqt.h" + +*/ +import "C" diff --git a/libmiqt/libmiqt.h b/libmiqt/libmiqt.h index 73bbcf3b..4ffc6528 100644 --- a/libmiqt/libmiqt.h +++ b/libmiqt/libmiqt.h @@ -10,12 +10,12 @@ extern "C" { struct miqt_string { size_t len; - char data; // Data continues after this element, all in the same allocation + char* data; }; struct miqt_array { size_t len; - void* data; // Separate, second allocation + void* data; }; struct miqt_string* miqt_strdup(const char* src, size_t len); diff --git a/libmiqt/strings.go b/libmiqt/strings.go deleted file mode 100644 index 5f6f5ddf..00000000 --- a/libmiqt/strings.go +++ /dev/null @@ -1,25 +0,0 @@ -package libmiqt - -// SPDX-License-Identifier: MIT - -/* - -#include "libmiqt.h" - -struct miqt_string* miqt_strdupg(_GoString_ gs) { - return miqt_strdup(_GoStringPtr(gs), _GoStringLen(gs)); -} - -*/ -import "C" - -import ( - "unsafe" -) - -// Strdupg will strdup a Go string into a miqt_string*. -// It is typed as returning an unsafe.Pointer because Cgo types cannot be shared -// across Go file boundaries. -func Strdupg(s string) unsafe.Pointer { - return unsafe.Pointer(C.miqt_strdupg(s)) -}