detached 42fe8d7

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 {
2929 API argsTemplate
3030 }
3131
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) {
3333 c := n
3434 stars := strings.Count(t, "*")
3535 gobjectNs := "gobject."
@@ -40,79 +40,102 @@ func (f *funcArgsTemplate) AddAPI(t string, n string, k Kind, ns string, nullabl
4040 if strings.ToLower(ns) == "glib" {
4141 glibNs = ""
4242 }
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 {
5245 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
5949 }
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+ }
6979 }
70- }
7180
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+ }
7585 }
86+
7687 f.API.Names = append(f.API.Names, n)
7788 f.API.Types = append(f.API.Types, t)
7889 f.API.Call = append(f.API.Call, c)
7990 f.API.Full = append(f.API.Full, n+" "+t)
8091 }
8192
82-func (f *funcArgsTemplate) AddPure(t string, n string, k Kind) {
93+func (f *funcArgsTemplate) AddPure(t string, n string, k Kind, isOut bool) {
8394 n += "p"
8495 c := n
8596 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
88101 if stars == 0 {
89- t = "uintptr"
102+ // For primitive Go types we need to manually add the *
103+ goPointerType = "*" + t
90104 }
91- case CallbackType:
92- c = fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", strings.TrimPrefix(t, "*"), n)
93105 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)
97115 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"
104120 } 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"
106138 }
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"
116139 }
117140 }
118141 f.Pure.Names = append(f.Pure.Names, n)
@@ -145,8 +168,10 @@ func (f *funcArgsTemplate) Add(p Parameter, ins string, ns string, kinds KindMap
145168 // Get a suitable variable name
146169 varName := p.VarName()
147170
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)
150175 }
151176
152177 func (f *funcArgsTemplate) AddThrows(ns string) {
@@ -29,7 +29,7 @@ type funcArgsTemplate struct {
29 API argsTemplate29 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 := n33 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 = n46+ // 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 = n53+ 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 varargs81+ // 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 := n95 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 = n108+ 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 name117+ 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 name168 // 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) {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close