From bb0132e0d5d972faf10a883385863ca97c827d51 Mon Sep 17 00:00:00 2001 From: mappu Date: Sat, 19 Oct 2024 12:24:49 +1300 Subject: [PATCH] genbindings/qbytearray: project as []byte --- cmd/genbindings/emitcabi.go | 24 +++++++++++++++++++++++ cmd/genbindings/emitgo.go | 34 ++++++++++++++++++++++++++++++++- cmd/genbindings/exceptions.go | 8 ++++++++ cmd/genbindings/intermediate.go | 2 +- 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/cmd/genbindings/emitcabi.go b/cmd/genbindings/emitcabi.go index f48728bc..0c59b092 100644 --- a/cmd/genbindings/emitcabi.go +++ b/cmd/genbindings/emitcabi.go @@ -11,6 +11,9 @@ func (p CppParameter) RenderTypeCabi() string { if p.ParameterType == "QString" { return "struct miqt_string" + } else if p.ParameterType == "QByteArray" { + return "struct miqt_string" + } else if _, ok := p.QListOf(); ok { return "struct miqt_array*" @@ -148,6 +151,9 @@ func emitParametersCabi(m CppMethod, selfType string) string { if p.ParameterType == "QString" { tmp = append(tmp, "struct miqt_string "+p.ParameterName) + } else if p.ParameterType == "QByteArray" { + 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) @@ -203,6 +209,12 @@ func emitCABI2CppForwarding(p CppParameter, indent string) (preamble string, for preamble += indent + "QString " + nameprefix + "_QString = QString::fromUtf8(" + p.ParameterName + ".data, " + p.ParameterName + ".len);\n" return preamble, nameprefix + "_QString" + } else if p.ParameterType == "QByteArray" { + // The caller will free the miqt_string data + // This ctor makes a deep copy, on the stack which will be dtor'd by RAII + preamble += indent + "QByteArray " + nameprefix + "_QByteArray(" + p.ParameterName + ".data, " + p.ParameterName + ".len);\n" + return preamble, nameprefix + "_QByteArray" + } else if listType, ok := p.QListOf(); ok { preamble += indent + p.GetQtCppType().ParameterType + " " + nameprefix + "_QList;\n" @@ -322,6 +334,18 @@ func emitAssignCppToCabi(assignExpression string, p CppParameter, rvalue string) afterCall += indent + "memcpy(" + namePrefix + "_ms.data, " + namePrefix + "_b.data(), " + namePrefix + "_ms.len);\n" afterCall += indent + assignExpression + namePrefix + "_ms;\n" + } else if p.ParameterType == "QByteArray" { + // C++ has given us a QByteArray. CABI needs this as a struct miqt_string + // Do not free the data, the caller will free it + + shouldReturn = ifv(p.Const, "const ", "") + "QByteArray " + p.ParameterName + "_qb = " + + afterCall += indent + "struct miqt_string " + namePrefix + "_ms;\n" + afterCall += indent + namePrefix + "_ms.len = " + namePrefix + "_qb.length();\n" + afterCall += indent + namePrefix + "_ms.data = static_cast(malloc(" + namePrefix + "_ms.len));\n" + afterCall += indent + "memcpy(" + namePrefix + "_ms.data, " + namePrefix + "_qb.data(), " + namePrefix + "_ms.len);\n" + afterCall += indent + assignExpression + namePrefix + "_ms;\n" + } else if t, ok := p.QListOf(); ok { // In some cases rvalue is a function call and the temporary diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index efe1a8be..70566a92 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -26,6 +26,9 @@ func (p CppParameter) RenderTypeGo(gfs *goFileState) string { if p.ParameterType == "QString" { return "string" } + if p.ParameterType == "QByteArray" { + return "[]byte" + } if t, ok := p.QListOf(); ok { return "[]" + t.RenderTypeGo(gfs) @@ -145,6 +148,10 @@ func (p CppParameter) parameterTypeCgo() string { return "C.struct_miqt_string" } + if p.ParameterType == "QByteArray" { + return "C.struct_miqt_string" + } + if _, ok := p.QListOf(); ok { return "*C.struct_miqt_array" } @@ -264,6 +271,18 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble rvalue = nameprefix + "_ms" + } else if p.ParameterType == "QByteArray" { + // Go: convert []byte -> miqt_string + // CABI: convert miqt_string -> QByteArray + // n.b. This can ALIAS the existing []byte data + + gfs.imports["unsafe"] = struct{}{} + preamble += nameprefix + "_alias := C.struct_miqt_string{}\n" + preamble += nameprefix + "_alias.data = (*C.char)(unsafe.Pointer(&" + p.ParameterName + "[0]))\n" + preamble += nameprefix + "_alias.len = C.size_t(len(" + p.ParameterName + "))\n" + + rvalue = nameprefix + "_alias" + } else if listType, ok := p.QListOf(); ok { // QList // Go: convert T[] -> t* and len @@ -367,6 +386,19 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue afterword += assignExpr + namePrefix + "_ret" return shouldReturn + " " + rvalue + "\n" + afterword + } else if rt.ParameterType == "QByteArray" { + // We receive the CABI type of a miqt_string. Convert it into []byte + // We must free the miqt_string data pointer - this is a data copy, + // not an alias + + gfs.imports["unsafe"] = struct{}{} + + shouldReturn = "var " + namePrefix + "_bytearray C.struct_miqt_string = " + afterword += namePrefix + "_ret := C.GoBytes(unsafe.Pointer(" + namePrefix + "_bytearray.data), C.int(int64(" + namePrefix + "_bytearray.len)))\n" + afterword += "C.free(unsafe.Pointer(" + namePrefix + "_bytearray.data))\n" + afterword += assignExpr + namePrefix + "_ret" + return shouldReturn + " " + rvalue + "\n" + afterword + } else if t, ok := rt.QListOf(); ok { gfs.imports["unsafe"] = struct{}{} @@ -645,7 +677,7 @@ import "C" if returnTypeDecl == "void" { returnTypeDecl = "" } - if m.ReturnType.QtClassType() && m.ReturnType.ParameterType != "QString" && !(m.ReturnType.Pointer || m.ReturnType.ByRef) { + if m.ReturnType.QtClassType() && m.ReturnType.ParameterType != "QString" && m.ReturnType.ParameterType != "QByteArray" && !(m.ReturnType.Pointer || m.ReturnType.ByRef) { returnTypeDecl = "*" + returnTypeDecl } diff --git a/cmd/genbindings/exceptions.go b/cmd/genbindings/exceptions.go index 085b2ad7..edb5c03c 100644 --- a/cmd/genbindings/exceptions.go +++ b/cmd/genbindings/exceptions.go @@ -47,6 +47,7 @@ func AllowHeader(fullpath string) bool { "qmaccocoaviewcontainer_mac.h", // Needs NSView* headers. TODO allow with darwin build tag "qmacnativewidget_mac.h", // Needs NSView* headers. TODO allow with darwin build tag "qstring.h", // QString does not exist in this binding + "qbytearray.h", // QByteArray does not exist in this binding "qlist.h", // QList does not exist in this binding "qvector.h": // QVector does not exist in this binding return false @@ -211,6 +212,13 @@ func CheckComplexity(p CppParameter, isReturnType bool) error { return ErrTooComplex } + // QBuffer can accept a raw pointer to an internal QByteArray, but that + // doesn't work when QByteArray is deleted + // QDataStream + if p.ParameterType == "QByteArray" && p.Pointer && !isReturnType { + return ErrTooComplex + } + if p.ParameterType == "QFormLayout::ItemRole" && p.Pointer && !isReturnType { // Out-parameters in QFormLayout return ErrTooComplex } diff --git a/cmd/genbindings/intermediate.go b/cmd/genbindings/intermediate.go index d2ee417c..87148f5e 100644 --- a/cmd/genbindings/intermediate.go +++ b/cmd/genbindings/intermediate.go @@ -110,7 +110,7 @@ func (p CppParameter) QtClassType() bool { return true } - if p.ParameterType == "QString" { + if p.ParameterType == "QString" || p.ParameterType == "QByteArray" { return true }