genbindings: add QPair<> support

This commit is contained in:
mappu 2024-11-15 18:41:36 +13:00
parent dc39b7ca65
commit 58ec6e1821
5 changed files with 127 additions and 5 deletions

View File

@ -226,9 +226,6 @@ func AllowMethod(className string, mm CppMethod) error {
// Any type not permitted by AllowClass is also not permitted by this method.
func AllowType(p CppParameter, isReturnType bool) error {
if p.QPairOf() {
return ErrTooComplex // e.g. QGradientStop
}
if t, ok := p.QSetOf(); ok {
if err := AllowType(t, isReturnType); err != nil {
return err
@ -258,6 +255,14 @@ func AllowType(p CppParameter, isReturnType bool) error {
return ErrTooComplex
}
}
if kType, vType, ok := p.QPairOf(); ok {
if err := AllowType(kType, isReturnType); err != nil {
return err
}
if err := AllowType(vType, isReturnType); err != nil {
return err
}
}
if p.QMultiMapOf() {
return ErrTooComplex // e.g. Qt5 QNetwork qsslcertificate.h has a QMultiMap<QSsl::AlternativeNameEntryType, QString>
}

View File

@ -23,6 +23,9 @@ func (p CppParameter) RenderTypeCabi() string {
} else if _, _, ok := p.QMapOf(); ok {
return "struct miqt_map"
} else if _, _, ok := p.QPairOf(); ok {
return "struct miqt_map"
} else if (p.Pointer || p.ByRef) && p.QtClassType() {
return cabiClassName(p.ParameterType) + "*"
@ -267,6 +270,25 @@ func emitCABI2CppForwarding(p CppParameter, indent string) (preamble string, for
preamble += indent + "}\n"
return preamble, nameprefix + "_QMap"
} else if kType, vType, ok := p.QPairOf(); ok {
preamble += indent + p.GetQtCppType().ParameterType + " " + nameprefix + "_QPair;\n"
preamble += indent + kType.RenderTypeCabi() + "* " + nameprefix + "_first_arr = static_cast<" + kType.RenderTypeCabi() + "*>(" + p.ParameterName + ".keys);\n"
preamble += indent + vType.RenderTypeCabi() + "* " + nameprefix + "_second_arr = static_cast<" + vType.RenderTypeCabi() + "*>(" + p.ParameterName + ".values);\n"
kType.ParameterName = nameprefix + "_first_arr[0]"
addPreK, addFwdK := emitCABI2CppForwarding(kType, indent+"\t")
preamble += addPreK
vType.ParameterName = nameprefix + "_second_arr[0]"
addPreV, addFwdV := emitCABI2CppForwarding(vType, indent+"\t")
preamble += addPreV
preamble += indent + nameprefix + "_QPair.first = " + addFwdK + ";\n"
preamble += indent + nameprefix + "_QPair.second = " + addFwdV + ";\n"
return preamble, nameprefix + "_QPair"
} else if p.IsFlagType() || p.IntType() || p.IsKnownEnum() {
castSrc := p.ParameterName
castType := p.RenderTypeQtCpp()
@ -452,6 +474,26 @@ func emitAssignCppToCabi(assignExpression string, p CppParameter, rvalue string)
afterCall += indent + assignExpression + "" + namePrefix + "_out;\n"
return indent + shouldReturn + rvalue + ";\n" + afterCall
} else if kType, vType, ok := p.QPairOf(); ok {
// QPair<T1,T2>
shouldReturn = p.RenderTypeQtCpp() + " " + namePrefix + "_ret = "
afterCall += indent + "// Convert QPair<> from C++ memory to manually-managed C memory\n"
afterCall += indent + "" + kType.RenderTypeCabi() + "* " + namePrefix + "_first_arr = static_cast<" + kType.RenderTypeCabi() + "*>(malloc(sizeof(" + kType.RenderTypeCabi() + ")));\n"
afterCall += indent + "" + vType.RenderTypeCabi() + "* " + namePrefix + "_second_arr = static_cast<" + vType.RenderTypeCabi() + "*>(malloc(sizeof(" + vType.RenderTypeCabi() + ")));\n"
afterCall += emitAssignCppToCabi(indent+namePrefix+"_first_arr[0] = ", kType, namePrefix+"_ret.first")
afterCall += emitAssignCppToCabi(indent+namePrefix+"_second_arr[0] = ", vType, namePrefix+"_ret.second")
afterCall += indent + "struct miqt_map " + namePrefix + "_out;\n"
afterCall += indent + "" + namePrefix + "_out.len = 1;\n"
afterCall += indent + "" + namePrefix + "_out.keys = static_cast<void*>(" + namePrefix + "_first_arr);\n"
afterCall += indent + "" + namePrefix + "_out.values = static_cast<void*>(" + namePrefix + "_second_arr);\n"
afterCall += indent + assignExpression + "" + namePrefix + "_out;\n"
return indent + shouldReturn + rvalue + ";\n" + afterCall
} else if p.QtClassType() && p.ByRef {
// It's a pointer in disguise, just needs one cast
shouldReturn = p.RenderTypeQtCpp() + " " + namePrefix + "_ret = "

View File

@ -43,6 +43,12 @@ func (p CppParameter) RenderTypeGo(gfs *goFileState) string {
return "map[" + t1.RenderTypeGo(gfs) + "]" + t2.RenderTypeGo(gfs)
}
if t1, t2, ok := p.QPairOf(); ok {
// Design QPair using capital-named members, in case it gets passed
// across packages
return "struct { First " + t1.RenderTypeGo(gfs) + " ; Second " + t2.RenderTypeGo(gfs) + " }"
}
if p.ParameterType == "void" && p.Pointer {
return "unsafe.Pointer"
}
@ -169,6 +175,10 @@ func (p CppParameter) parameterTypeCgo() string {
return "C.struct_miqt_map"
}
if _, _, ok := p.QPairOf(); ok {
return "C.struct_miqt_map"
}
// Cgo internally binds void* as unsafe.Pointer{}
if p.ParameterType == "void" && p.Pointer {
return "unsafe.Pointer"
@ -366,6 +376,30 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble
rvalue = nameprefix + "_mm"
} else if kType, vType, ok := p.QPairOf(); ok {
// QPair<T>
gfs.imports["unsafe"] = struct{}{}
preamble += nameprefix + "_First_CArray := (*[0xffff]" + kType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + kType.mallocSizeCgoExpression() + ")))\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_First_CArray))\n"
preamble += nameprefix + "_Second_CArray := (*[0xffff]" + vType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + vType.mallocSizeCgoExpression() + ")))\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Second_CArray))\n"
kType.ParameterName = p.ParameterName + ".First"
addPreamble, innerRvalue := gfs.emitParameterGo2CABIForwarding(kType)
preamble += addPreamble
preamble += nameprefix + "_First_CArray[0] = " + innerRvalue + "\n"
vType.ParameterName = p.ParameterName + ".Second"
addPreamble, innerRvalue = gfs.emitParameterGo2CABIForwarding(vType)
preamble += addPreamble
preamble += nameprefix + "_Second_CArray[0] = " + innerRvalue + "\n"
preamble += nameprefix + "_pair := C.struct_miqt_map{\nlen: 1,\nkeys: unsafe.Pointer(" + nameprefix + "_First_CArray),\nvalues: unsafe.Pointer(" + nameprefix + "_Second_CArray),\n}\n"
rvalue = nameprefix + "_pair"
} else if p.Pointer && p.ParameterType == "char" {
// Single char* argument
@ -506,6 +540,20 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
afterword += assignExpr + " " + namePrefix + "_ret\n"
return shouldReturn + " " + rvalue + "\n" + afterword
} else if kType, vType, ok := rt.QPairOf(); ok {
gfs.imports["unsafe"] = struct{}{}
shouldReturn = "var " + namePrefix + "_mm C.struct_miqt_map = "
afterword += namePrefix + "_First_CArray := (*[0xffff]" + kType.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_mm.keys))\n"
afterword += namePrefix + "_Second_CArray := (*[0xffff]" + vType.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_mm.values))\n"
afterword += gfs.emitCabiToGo(namePrefix+"_entry_First := ", kType, namePrefix+"_First_CArray[0]") + "\n"
afterword += gfs.emitCabiToGo(namePrefix+"_entry_Second := ", vType, namePrefix+"_Second_CArray[0]") + "\n"
afterword += assignExpr + " " + rt.RenderTypeGo(gfs) + " { First: " + namePrefix + "_entry_First , Second: " + namePrefix + "_entry_Second }\n"
return shouldReturn + " " + rvalue + "\n" + afterword
} else if rt.QtClassType() {
// Construct our Go type based on this inner CABI type
shouldReturn = "" + namePrefix + "_ret := "

View File

@ -151,8 +151,21 @@ func (p CppParameter) QMapOf() (CppParameter, CppParameter, bool) {
return CppParameter{}, CppParameter{}, false
}
func (p CppParameter) QPairOf() bool {
return strings.HasPrefix(p.ParameterType, `QPair<`) // TODO support this
func (p CppParameter) QPairOf() (CppParameter, CppParameter, bool) {
if strings.HasPrefix(p.ParameterType, `QPair<`) && strings.HasSuffix(p.ParameterType, `>`) {
interior := tokenizeMultipleParameters(p.ParameterType[6 : len(p.ParameterType)-1])
if len(interior) != 2 {
panic("QPair<> has unexpected number of template arguments")
}
first := parseSingleTypeString(interior[0])
first.ParameterName = p.ParameterName + "_first"
second := parseSingleTypeString(interior[1])
second.ParameterName = p.ParameterName + "_second"
return first, second, true
}
return CppParameter{}, CppParameter{}, false
}
func (p CppParameter) QSetOf() (CppParameter, bool) {

View File

@ -44,6 +44,20 @@ func applyTypedefs(p CppParameter) CppParameter {
p.QtCppOriginalType = &tmp
}
p.ParameterType = p.ParameterType[0:bpos] + `<` + kType2.RenderTypeQtCpp() + `, ` + vType2.RenderTypeQtCpp() + `>`
} else if kType, vType, ok := p.QPairOf(); ok {
kType2 := applyTypedefs(kType)
kType2.QtCppOriginalType = nil
vType2 := applyTypedefs(vType)
vType2.QtCppOriginalType = nil
if p.QtCppOriginalType == nil {
tmp := p // copy
p.QtCppOriginalType = &tmp
}
p.ParameterType = `QPair<` + kType2.RenderTypeQtCpp() + `, ` + vType2.RenderTypeQtCpp() + `>`
}
return p