GIR: Use pointers for `out` parameters
Signed-off-by: Felicitas Pojtinger <felicitas@pojtinger.com>
- commit
- 42fe8d72216a7cbfa0bbc7b9a1f8df14b1deda45
- author
- Felicitas Pojtinger · · 2025-10-25 23:18 UTC
- committer
- Jeroen Wijenbergh · · 2025-12-01 16:14 UTC
- parent
- ce1ffcb
- signature
- unsigned
1 file · +81 -56
M internal/gir/types/template.go +81 -56
| @@ -29,7 +29,7 @@ type funcArgsTemplate struct { | |||
| 29 | 29 | API argsTemplate | |
| 30 | 30 | } | |
| 31 | 31 | ||
| 32 | - | func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullable bool) { | |
| 32 | + | func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullable bool, isOut bool) { | |
| 33 | 33 | c := n | |
| 34 | 34 | stars := strings.Count(t, "*") | |
| 35 | 35 | gobjectNs := "gobject." | |
| @@ -40,79 +40,102 @@ func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullabl | |||
| 40 | 40 | if strings.ToLower(ns) == "glib" { | |
| 41 | 41 | glibNs = "" | |
| 42 | 42 | } | |
| 43 | - | switch k { | |
| 44 | - | case CallbackType: | |
| 45 | - | if nullable { | |
| 46 | - | c = fmt.Sprintf("%sNewCallbackNullable(%s)", glibNs, n) | |
| 47 | - | } else { | |
| 48 | - | c = fmt.Sprintf("%sNewCallback(%s)", glibNs, n) | |
| 49 | - | } | |
| 50 | - | t = "*" + t | |
| 51 | - | case ClassesType: | |
| 43 | + | ||
| 44 | + | if isOut { | |
| 52 | 45 | if stars == 0 { | |
| 53 | - | c = n | |
| 54 | - | t = "uintptr" | |
| 55 | - | } else if stars > 1 { | |
| 56 | - | c = fmt.Sprintf("%sConvertPtr(%s)", gobjectNs, n) | |
| 57 | - | } else if stars == 1 { | |
| 58 | - | c = n + ".GoPointer()" | |
| 46 | + | // For out parameters, the C type already has a pointer, and so do non-primitive Go types. | |
| 47 | + | // For primitive Go types we need to manually add the * | |
| 48 | + | t = "*" + t | |
| 59 | 49 | } | |
| 60 | - | case InterfacesType: | |
| 61 | - | t = strings.TrimPrefix(t, "*") | |
| 62 | - | if stars == 0 { | |
| 63 | - | c = n | |
| 64 | - | t = "uintptr" | |
| 65 | - | } else if stars > 1 { | |
| 66 | - | c = fmt.Sprintf("%sConvertPtr(%s)", gobjectNs, n) | |
| 67 | - | } else if stars == 1 { | |
| 68 | - | c = n + ".GoPointer()" | |
| 50 | + | c = fmt.Sprintf("uintptr(unsafe.Pointer(%s))", n) | |
| 51 | + | } else { | |
| 52 | + | switch k { | |
| 53 | + | case CallbackType: | |
| 54 | + | if nullable { | |
| 55 | + | c = fmt.Sprintf("%sNewCallbackNullable(%s)", glibNs, n) | |
| 56 | + | } else { | |
| 57 | + | c = fmt.Sprintf("%sNewCallback(%s)", glibNs, n) | |
| 58 | + | } | |
| 59 | + | t = "*" + t | |
| 60 | + | case ClassesType: | |
| 61 | + | if stars == 0 { | |
| 62 | + | c = n | |
| 63 | + | t = "uintptr" | |
| 64 | + | } else if stars > 1 { | |
| 65 | + | c = fmt.Sprintf("%sConvertPtr(%s)", gobjectNs, n) | |
| 66 | + | } else if stars == 1 { | |
| 67 | + | c = n + ".GoPointer()" | |
| 68 | + | } | |
| 69 | + | case InterfacesType: | |
| 70 | + | t = strings.TrimPrefix(t, "*") | |
| 71 | + | if stars == 0 { | |
| 72 | + | c = n | |
| 73 | + | t = "uintptr" | |
| 74 | + | } else if stars > 1 { | |
| 75 | + | c = fmt.Sprintf("%sConvertPtr(%s)", gobjectNs, n) | |
| 76 | + | } else if stars == 1 { | |
| 77 | + | c = n + ".GoPointer()" | |
| 78 | + | } | |
| 69 | 79 | } | |
| 70 | - | } | |
| 71 | 80 | ||
| 72 | - | // special case for varargs | |
| 73 | - | if n == "varArgs" { | |
| 74 | - | c = n + "..." | |
| 81 | + | // special case for varargs | |
| 82 | + | if n == "varArgs" { | |
| 83 | + | c = n + "..." | |
| 84 | + | } | |
| 75 | 85 | } | |
| 86 | + | ||
| 76 | 87 | f.API.Names = append(f.API.Names, n) | |
| 77 | 88 | f.API.Types = append(f.API.Types, t) | |
| 78 | 89 | f.API.Call = append(f.API.Call, c) | |
| 79 | 90 | f.API.Full = append(f.API.Full, n+" "+t) | |
| 80 | 91 | } | |
| 81 | 92 | ||
| 82 | - | func (f *funcArgsTemplate) AddPure(t string, n string, k Kind) { | |
| 93 | + | func (f *funcArgsTemplate) AddPure(t string, n string, k Kind, isOut bool) { | |
| 83 | 94 | n += "p" | |
| 84 | 95 | c := n | |
| 85 | 96 | stars := strings.Count(t, "*") | |
| 86 | - | switch k { | |
| 87 | - | case RecordsType: | |
| 97 | + | ||
| 98 | + | if isOut { | |
| 99 | + | // Out parameters are always pointers in C, so we can use uintptr for the type | |
| 100 | + | goPointerType := t | |
| 88 | 101 | if stars == 0 { | |
| 89 | - | t = "uintptr" | |
| 102 | + | // For primitive Go types we need to manually add the * | |
| 103 | + | goPointerType = "*" + t | |
| 90 | 104 | } | |
| 91 | - | case CallbackType: | |
| 92 | - | c = fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", strings.TrimPrefix(t, "*"), n) | |
| 93 | 105 | t = "uintptr" | |
| 94 | - | case ClassesType: | |
| 95 | - | if stars == 0 { | |
| 96 | - | c = n | |
| 106 | + | c = fmt.Sprintf("(%s)(unsafe.Pointer(%s))", goPointerType, n) | |
| 107 | + | } else { | |
| 108 | + | switch k { | |
| 109 | + | case RecordsType: | |
| 110 | + | if stars == 0 { | |
| 111 | + | t = "uintptr" | |
| 112 | + | } | |
| 113 | + | case CallbackType: | |
| 114 | + | c = fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", strings.TrimPrefix(t, "*"), n) | |
| 97 | 115 | t = "uintptr" | |
| 98 | - | } else { | |
| 99 | - | // Remove all dereference operators to get the base class name | |
| 100 | - | baseName := strings.TrimPrefix(t, strings.Repeat("*", stars)) | |
| 101 | - | if stars > 1 { | |
| 102 | - | // For double pointers like **ParamSpec, we need to pass the double pointer directly | |
| 103 | - | c = fmt.Sprintf("(**%s)(unsafe.Pointer(%s))", baseName, n) | |
| 116 | + | case ClassesType: | |
| 117 | + | if stars == 0 { | |
| 118 | + | c = n | |
| 119 | + | t = "uintptr" | |
| 104 | 120 | } else { | |
| 105 | - | c = fmt.Sprintf("%sNewFromInternalPtr(%s)", baseName, n) | |
| 121 | + | // Remove all dereference operators to get the base class name | |
| 122 | + | baseName := strings.TrimPrefix(t, strings.Repeat("*", stars)) | |
| 123 | + | if stars > 1 { | |
| 124 | + | // For double pointers like **ParamSpec, we need to pass the double pointer directly | |
| 125 | + | c = fmt.Sprintf("(**%s)(unsafe.Pointer(%s))", baseName, n) | |
| 126 | + | } else { | |
| 127 | + | c = fmt.Sprintf("%sNewFromInternalPtr(%s)", baseName, n) | |
| 128 | + | } | |
| 129 | + | t = "uintptr" | |
| 130 | + | } | |
| 131 | + | case InterfacesType: | |
| 132 | + | if stars == 0 { | |
| 133 | + | c = n | |
| 134 | + | t = "uintptr" | |
| 135 | + | } else { | |
| 136 | + | c = fmt.Sprintf("%s{Ptr: %s}", t+"Base", n) | |
| 137 | + | t = strings.Repeat("*", stars-1) + "uintptr" | |
| 106 | 138 | } | |
| 107 | - | t = "uintptr" | |
| 108 | - | } | |
| 109 | - | case InterfacesType: | |
| 110 | - | if stars == 0 { | |
| 111 | - | c = n | |
| 112 | - | t = "uintptr" | |
| 113 | - | } else { | |
| 114 | - | c = fmt.Sprintf("%s{Ptr: %s}", t+"Base", n) | |
| 115 | - | t = strings.Repeat("*", stars-1) + "uintptr" | |
| 116 | 139 | } | |
| 117 | 140 | } | |
| 118 | 141 | f.Pure.Names = append(f.Pure.Names, n) | |
| @@ -145,8 +168,10 @@ func (f *funcArgsTemplate) Add(p Parameter, ins string, ns string, kinds KindMap | |||
| 145 | 168 | // Get a suitable variable name | |
| 146 | 169 | varName := p.VarName() | |
| 147 | 170 | ||
| 148 | - | f.AddAPI(goType, varName, kind, ns, p.Nullable) | |
| 149 | - | f.AddPure(goType, varName, kind) | |
| 171 | + | isOut := p.Direction == "out" | |
| 172 | + | ||
| 173 | + | f.AddAPI(goType, varName, kind, ns, p.Nullable, isOut) | |
| 174 | + | f.AddPure(goType, varName, kind, isOut) | |
| 150 | 175 | } | |
| 151 | 176 | ||
| 152 | 177 | func (f *funcArgsTemplate) AddThrows(ns string) { | |
| @@ -29,7 +29,7 @@ type funcArgsTemplate struct { | |||||
| 29 | API argsTemplate | 29 | API argsTemplate | ||
| 30 | } | 30 | } | ||
| 31 | 31 | ||||
| 32 | - | func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullable bool) { | 32 | + | func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullable bool, isOut bool) { |
| 33 | c := n | 33 | c := n | ||
| 34 | stars := strings.Count(t, "*") | 34 | stars := strings.Count(t, "*") | ||
| 35 | gobjectNs := "gobject." | 35 | gobjectNs := "gobject." | ||
| @@ -40,79 +40,102 @@ func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullabl | |||||
| 40 | if strings.ToLower(ns) == "glib" { | 40 | if strings.ToLower(ns) == "glib" { | ||
| 41 | glibNs = "" | 41 | glibNs = "" | ||
| 42 | } | 42 | } | ||
| 43 | - | switch k { | 43 | + | |
| 44 | - | case CallbackType: | 44 | + | if isOut { |
| 45 | - | if nullable { | |||
| 46 | - | c = fmt.Sprintf("%sNewCallbackNullable(%s)", glibNs, n) | |||
| 47 | - | } else { | |||
| 48 | - | c = fmt.Sprintf("%sNewCallback(%s)", glibNs, n) | |||
| 49 | - | } | |||
| 50 | - | t = "*" + t | |||
| 51 | - | case ClassesType: | |||
| 52 | if stars == 0 { | 45 | if stars == 0 { | ||
| 53 | - | c = n | 46 | + | // For out parameters, the C type already has a pointer, and so do non-primitive Go types. |
| 54 | - | t = "uintptr" | 47 | + | // For primitive Go types we need to manually add the * |
| 55 | - | } else if stars > 1 { | 48 | + | t = "*" + t |
| 56 | - | c = fmt.Sprintf("%sConvertPtr(%s)", gobjectNs, n) | |||
| 57 | - | } else if stars == 1 { | |||
| 58 | - | c = n + ".GoPointer()" | |||
| 59 | } | 49 | } | ||
| 60 | - | case InterfacesType: | 50 | + | c = fmt.Sprintf("uintptr(unsafe.Pointer(%s))", n) |
| 61 | - | t = strings.TrimPrefix(t, "*") | 51 | + | } else { |
| 62 | - | if stars == 0 { | 52 | + | switch k { |
| 63 | - | c = n | 53 | + | case CallbackType: |
| 64 | - | t = "uintptr" | 54 | + | if nullable { |
| 65 | - | } else if stars > 1 { | 55 | + | c = fmt.Sprintf("%sNewCallbackNullable(%s)", glibNs, n) |
| 66 | - | c = fmt.Sprintf("%sConvertPtr(%s)", gobjectNs, n) | 56 | + | } else { |
| 67 | - | } else if stars == 1 { | 57 | + | c = fmt.Sprintf("%sNewCallback(%s)", glibNs, n) |
| 68 | - | c = n + ".GoPointer()" | 58 | + | } |
| 59 | + | t = "*" + t | |||
| 60 | + | case ClassesType: | |||
| 61 | + | if stars == 0 { | |||
| 62 | + | c = n | |||
| 63 | + | t = "uintptr" | |||
| 64 | + | } else if stars > 1 { | |||
| 65 | + | c = fmt.Sprintf("%sConvertPtr(%s)", gobjectNs, n) | |||
| 66 | + | } else if stars == 1 { | |||
| 67 | + | c = n + ".GoPointer()" | |||
| 68 | + | } | |||
| 69 | + | case InterfacesType: | |||
| 70 | + | t = strings.TrimPrefix(t, "*") | |||
| 71 | + | if stars == 0 { | |||
| 72 | + | c = n | |||
| 73 | + | t = "uintptr" | |||
| 74 | + | } else if stars > 1 { | |||
| 75 | + | c = fmt.Sprintf("%sConvertPtr(%s)", gobjectNs, n) | |||
| 76 | + | } else if stars == 1 { | |||
| 77 | + | c = n + ".GoPointer()" | |||
| 78 | + | } | |||
| 69 | } | 79 | } | ||
| 70 | - | } | |||
| 71 | 80 | ||||
| 72 | - | // special case for varargs | 81 | + | // special case for varargs |
| 73 | - | if n == "varArgs" { | 82 | + | if n == "varArgs" { |
| 74 | - | c = n + "..." | 83 | + | c = n + "..." |
| 84 | + | } | |||
| 75 | } | 85 | } | ||
| 86 | + | ||||
| 76 | f.API.Names = append(f.API.Names, n) | 87 | f.API.Names = append(f.API.Names, n) | ||
| 77 | f.API.Types = append(f.API.Types, t) | 88 | f.API.Types = append(f.API.Types, t) | ||
| 78 | f.API.Call = append(f.API.Call, c) | 89 | f.API.Call = append(f.API.Call, c) | ||
| 79 | f.API.Full = append(f.API.Full, n+" "+t) | 90 | f.API.Full = append(f.API.Full, n+" "+t) | ||
| 80 | } | 91 | } | ||
| 81 | 92 | ||||
| 82 | - | func (f *funcArgsTemplate) AddPure(t string, n string, k Kind) { | 93 | + | func (f *funcArgsTemplate) AddPure(t string, n string, k Kind, isOut bool) { |
| 83 | n += "p" | 94 | n += "p" | ||
| 84 | c := n | 95 | c := n | ||
| 85 | stars := strings.Count(t, "*") | 96 | stars := strings.Count(t, "*") | ||
| 86 | - | switch k { | 97 | + | |
| 87 | - | case RecordsType: | 98 | + | if isOut { |
| 99 | + | // Out parameters are always pointers in C, so we can use uintptr for the type | |||
| 100 | + | goPointerType := t | |||
| 88 | if stars == 0 { | 101 | if stars == 0 { | ||
| 89 | - | t = "uintptr" | 102 | + | // For primitive Go types we need to manually add the * |
| 103 | + | goPointerType = "*" + t | |||
| 90 | } | 104 | } | ||
| 91 | - | case CallbackType: | |||
| 92 | - | c = fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", strings.TrimPrefix(t, "*"), n) | |||
| 93 | t = "uintptr" | 105 | t = "uintptr" | ||
| 94 | - | case ClassesType: | 106 | + | c = fmt.Sprintf("(%s)(unsafe.Pointer(%s))", goPointerType, n) |
| 95 | - | if stars == 0 { | 107 | + | } else { |
| 96 | - | c = n | 108 | + | switch k { |
| 109 | + | case RecordsType: | |||
| 110 | + | if stars == 0 { | |||
| 111 | + | t = "uintptr" | |||
| 112 | + | } | |||
| 113 | + | case CallbackType: | |||
| 114 | + | c = fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", strings.TrimPrefix(t, "*"), n) | |||
| 97 | t = "uintptr" | 115 | t = "uintptr" | ||
| 98 | - | } else { | 116 | + | case ClassesType: |
| 99 | - | // Remove all dereference operators to get the base class name | 117 | + | if stars == 0 { |
| 100 | - | baseName := strings.TrimPrefix(t, strings.Repeat("*", stars)) | 118 | + | c = n |
| 101 | - | if stars > 1 { | 119 | + | t = "uintptr" |
| 102 | - | // For double pointers like **ParamSpec, we need to pass the double pointer directly | |||
| 103 | - | c = fmt.Sprintf("(**%s)(unsafe.Pointer(%s))", baseName, n) | |||
| 104 | } else { | 120 | } else { | ||
| 105 | - | c = fmt.Sprintf("%sNewFromInternalPtr(%s)", baseName, n) | 121 | + | // Remove all dereference operators to get the base class name |
| 122 | + | baseName := strings.TrimPrefix(t, strings.Repeat("*", stars)) | |||
| 123 | + | if stars > 1 { | |||
| 124 | + | // For double pointers like **ParamSpec, we need to pass the double pointer directly | |||
| 125 | + | c = fmt.Sprintf("(**%s)(unsafe.Pointer(%s))", baseName, n) | |||
| 126 | + | } else { | |||
| 127 | + | c = fmt.Sprintf("%sNewFromInternalPtr(%s)", baseName, n) | |||
| 128 | + | } | |||
| 129 | + | t = "uintptr" | |||
| 130 | + | } | |||
| 131 | + | case InterfacesType: | |||
| 132 | + | if stars == 0 { | |||
| 133 | + | c = n | |||
| 134 | + | t = "uintptr" | |||
| 135 | + | } else { | |||
| 136 | + | c = fmt.Sprintf("%s{Ptr: %s}", t+"Base", n) | |||
| 137 | + | t = strings.Repeat("*", stars-1) + "uintptr" | |||
| 106 | } | 138 | } | ||
| 107 | - | t = "uintptr" | |||
| 108 | - | } | |||
| 109 | - | case InterfacesType: | |||
| 110 | - | if stars == 0 { | |||
| 111 | - | c = n | |||
| 112 | - | t = "uintptr" | |||
| 113 | - | } else { | |||
| 114 | - | c = fmt.Sprintf("%s{Ptr: %s}", t+"Base", n) | |||
| 115 | - | t = strings.Repeat("*", stars-1) + "uintptr" | |||
| 116 | } | 139 | } | ||
| 117 | } | 140 | } | ||
| 118 | f.Pure.Names = append(f.Pure.Names, n) | 141 | f.Pure.Names = append(f.Pure.Names, n) | ||
| @@ -145,8 +168,10 @@ func (f *funcArgsTemplate) Add(p Parameter, ins string, ns string, kinds KindMap | |||||
| 145 | // Get a suitable variable name | 168 | // Get a suitable variable name | ||
| 146 | varName := p.VarName() | 169 | varName := p.VarName() | ||
| 147 | 170 | ||||
| 148 | - | f.AddAPI(goType, varName, kind, ns, p.Nullable) | 171 | + | isOut := p.Direction == "out" |
| 149 | - | f.AddPure(goType, varName, kind) | 172 | + | |
| 173 | + | f.AddAPI(goType, varName, kind, ns, p.Nullable, isOut) | |||
| 174 | + | f.AddPure(goType, varName, kind, isOut) | |||
| 150 | } | 175 | } | ||
| 151 | 176 | ||||
| 152 | func (f *funcArgsTemplate) AddThrows(ns string) { | 177 | func (f *funcArgsTemplate) AddThrows(ns string) { | ||