v0.7.0 4889c1a

struct_test.go RawHistoryFolder

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
3
4//go:build darwin && (arm64 || amd64)
5
6package purego_test
7
8import (
9	"os"
10	"path/filepath"
11	"runtime"
12	"testing"
13	"unsafe"
14
15	"github.com/ebitengine/purego"
16)
17
18func TestRegisterFunc_structArgs(t *testing.T) {
19	libFileName := filepath.Join(t.TempDir(), "structtest.so")
20	t.Logf("Build %v", libFileName)
21
22	if err := buildSharedLib("CC", libFileName, filepath.Join("testdata", "structtest", "struct_test.c")); err != nil {
23		t.Fatal(err)
24	}
25	defer os.Remove(libFileName)
26
27	lib, err := purego.Dlopen(libFileName, purego.RTLD_NOW|purego.RTLD_GLOBAL)
28	if err != nil {
29		t.Fatalf("Dlopen(%q) failed: %v", libFileName, err)
30	}
31
32	const (
33		expectedUnsigned         = 0xdeadbeef
34		expectedSigned           = -123
35		expectedOdd              = 12 + 23 + 46
36		expectedLong     uint64  = 0xdeadbeefcafebabe
37		expectedFloat    float32 = 10
38		expectedDouble   float64 = 10
39	)
40
41	{
42		type Empty struct{}
43		var NoStruct func(Empty) int64
44		purego.RegisterLibFunc(&NoStruct, lib, "NoStruct")
45		if ret := NoStruct(Empty{}); ret != expectedUnsigned {
46			t.Fatalf("NoStruct returned %#x wanted %#x", ret, expectedUnsigned)
47		}
48	}
49	{
50		type EmptyEmpty struct{}
51		var EmptyEmptyFn func(EmptyEmpty) int64
52		purego.RegisterLibFunc(&EmptyEmptyFn, lib, "EmptyEmpty")
53		if ret := EmptyEmptyFn(EmptyEmpty{}); ret != expectedUnsigned {
54			t.Fatalf("EmptyEmpty returned %#x wanted %#x", ret, expectedUnsigned)
55		}
56		var EmptyEmptyWithReg func(uint32, EmptyEmpty, uint32) int64
57		purego.RegisterLibFunc(&EmptyEmptyWithReg, lib, "EmptyEmptyWithReg")
58		if ret := EmptyEmptyWithReg(0xdead, EmptyEmpty{}, 0xbeef); ret != expectedUnsigned {
59			t.Fatalf("EmptyEmptyWithReg returned %#x wanted %#x", ret, expectedUnsigned)
60		}
61	}
62	{
63		type GreaterThan16Bytes struct {
64			x, y, z *int64
65		}
66		var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000
67		var GreaterThan16BytesFn func(GreaterThan16Bytes) int64
68		purego.RegisterLibFunc(&GreaterThan16BytesFn, lib, "GreaterThan16Bytes")
69		if ret := GreaterThan16BytesFn(GreaterThan16Bytes{x: &x, y: &y, z: &z}); ret != expectedUnsigned {
70			t.Fatalf("GreaterThan16Bytes returned %#x wanted %#x", ret, expectedUnsigned)
71		}
72	}
73	{
74		type GreaterThan16BytesStruct struct {
75			a struct {
76				x, y, z *int64
77			}
78		}
79		var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000
80		var GreaterThan16BytesStructFn func(GreaterThan16BytesStruct) int64
81		purego.RegisterLibFunc(&GreaterThan16BytesStructFn, lib, "GreaterThan16BytesStruct")
82		if ret := GreaterThan16BytesStructFn(GreaterThan16BytesStruct{a: struct{ x, y, z *int64 }{x: &x, y: &y, z: &z}}); ret != expectedUnsigned {
83			t.Fatalf("GreaterThan16BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned)
84		}
85	}
86	{
87		type GreaterThan16Bytes struct {
88			x, y, z *int64
89		}
90		var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000
91		var AfterRegisters func(a, b, c, d, e, f, g, h int, bytes GreaterThan16Bytes) int64
92		purego.RegisterLibFunc(&AfterRegisters, lib, "AfterRegisters")
93		if ret := AfterRegisters(0xD0000000, 0xE000000, 0xA00000, 0xD0000, 0xB000, 0xE00, 0xE0, 0xF, GreaterThan16Bytes{x: &x, y: &y, z: &z}); ret != expectedUnsigned {
94			t.Fatalf("AfterRegisters returned %#x wanted %#x", ret, expectedUnsigned)
95		}
96		var BeforeRegisters func(bytes GreaterThan16Bytes, a, b int64) uint64
97		z -= 0xFF
98		purego.RegisterLibFunc(&BeforeRegisters, lib, "BeforeRegisters")
99		if ret := BeforeRegisters(GreaterThan16Bytes{&x, &y, &z}, 0x0F, 0xF0); ret != expectedUnsigned {
100			t.Fatalf("BeforeRegisters returned %#x wanted %#x", ret, expectedUnsigned)
101		}
102	}
103	{
104		type IntLessThan16Bytes struct {
105			x, y int64
106		}
107		var IntLessThan16BytesFn func(bytes IntLessThan16Bytes) int64
108		purego.RegisterLibFunc(&IntLessThan16BytesFn, lib, "IntLessThan16Bytes")
109		if ret := IntLessThan16BytesFn(IntLessThan16Bytes{0xDEAD0000, 0xBEEF}); ret != expectedUnsigned {
110			t.Fatalf("IntLessThan16BytesFn returned %#x wanted %#x", ret, expectedUnsigned)
111		}
112	}
113	{
114		type FloatLessThan16Bytes struct {
115			x, y float32
116		}
117		var FloatLessThan16BytesFn func(FloatLessThan16Bytes) float32
118		purego.RegisterLibFunc(&FloatLessThan16BytesFn, lib, "FloatLessThan16Bytes")
119		if ret := FloatLessThan16BytesFn(FloatLessThan16Bytes{3, 7}); ret != expectedFloat {
120			t.Fatalf("FloatLessThan16Bytes returned %f wanted %f", ret, expectedFloat)
121		}
122	}
123	{
124		type ThreeSmallFields struct {
125			x, y, z float32
126		}
127		var ThreeSmallFieldsFn func(ThreeSmallFields) float32
128		purego.RegisterLibFunc(&ThreeSmallFieldsFn, lib, "ThreeSmallFields")
129		if ret := ThreeSmallFieldsFn(ThreeSmallFields{1, 2, 7}); ret != expectedFloat {
130			t.Fatalf("ThreeSmallFields returned %f wanted %f", ret, expectedFloat)
131		}
132	}
133	{
134		type FloatAndInt struct {
135			x float32
136			y int32
137		}
138		var FloatAndIntFn func(FloatAndInt) float32
139		purego.RegisterLibFunc(&FloatAndIntFn, lib, "FloatAndInt")
140		if ret := FloatAndIntFn(FloatAndInt{3, 7}); ret != expectedFloat {
141			t.Fatalf("FloatAndIntFn returned %f wanted %f", ret, expectedFloat)
142		}
143	}
144	{
145		type DoubleStruct struct {
146			x float64
147		}
148		var DoubleStructFn func(DoubleStruct) float64
149		purego.RegisterLibFunc(&DoubleStructFn, lib, "DoubleStruct")
150		if ret := DoubleStructFn(DoubleStruct{10}); ret != expectedDouble {
151			t.Fatalf("DoubleStruct returned %f wanted %f", ret, expectedDouble)
152		}
153	}
154	{
155		type TwoDoubleStruct struct {
156			x, y float64
157		}
158		var TwoDoubleStructFn func(TwoDoubleStruct) float64
159		purego.RegisterLibFunc(&TwoDoubleStructFn, lib, "TwoDoubleStruct")
160		if ret := TwoDoubleStructFn(TwoDoubleStruct{3, 7}); ret != expectedDouble {
161			t.Fatalf("TwoDoubleStruct returned %f wanted %f", ret, expectedDouble)
162		}
163	}
164	{
165		type TwoDoubleTwoStruct struct {
166			x struct {
167				x, y float64
168			}
169		}
170		var TwoDoubleTwoStructFn func(TwoDoubleTwoStruct) float64
171		purego.RegisterLibFunc(&TwoDoubleTwoStructFn, lib, "TwoDoubleTwoStruct")
172		if ret := TwoDoubleTwoStructFn(TwoDoubleTwoStruct{x: struct{ x, y float64 }{x: 3, y: 7}}); ret != expectedDouble {
173			t.Fatalf("TwoDoubleTwoStruct returned %f wanted %f", ret, expectedDouble)
174		}
175	}
176	{
177		type ThreeDoubleStruct struct {
178			x, y, z float64
179		}
180		var ThreeDoubleStructFn func(ThreeDoubleStruct) float64
181		purego.RegisterLibFunc(&ThreeDoubleStructFn, lib, "ThreeDoubleStruct")
182		if ret := ThreeDoubleStructFn(ThreeDoubleStruct{1, 3, 6}); ret != expectedDouble {
183			t.Fatalf("ThreeDoubleStructFn returned %f wanted %f", ret, expectedDouble)
184		}
185	}
186	{
187		type LargeFloatStruct struct {
188			a, b, c, d, e, f float64
189		}
190		var LargeFloatStructFn func(LargeFloatStruct) float64
191		purego.RegisterLibFunc(&LargeFloatStructFn, lib, "LargeFloatStruct")
192		if ret := LargeFloatStructFn(LargeFloatStruct{1, 2, 3, 4, 5, -5}); ret != expectedDouble {
193			t.Fatalf("LargeFloatStructFn returned %f wanted %f", ret, expectedFloat)
194		}
195		var LargeFloatStructWithRegs func(a, b, c float64, s LargeFloatStruct) float64
196		purego.RegisterLibFunc(&LargeFloatStructWithRegs, lib, "LargeFloatStructWithRegs")
197		if ret := LargeFloatStructWithRegs(1, -1, 0, LargeFloatStruct{1, 2, 3, 4, 5, -5}); ret != expectedDouble {
198			t.Fatalf("LargeFloatStructWithRegs returned %f wanted %f", ret, expectedFloat)
199		}
200	}
201	{
202		type Rect struct {
203			x, y, w, h float64
204		}
205		var RectangleWithRegs func(a, b, c, d, e float64, rect Rect) float64
206		purego.RegisterLibFunc(&RectangleWithRegs, lib, "RectangleWithRegs")
207		if ret := RectangleWithRegs(1, 2, 3, 4, -2, Rect{1, 2, 3, -4}); ret != expectedDouble {
208			t.Fatalf("RectangleWithRegs returned %f wanted %f", ret, expectedDouble)
209		}
210		var RectangleSubtract func(rect Rect) float64
211		purego.RegisterLibFunc(&RectangleSubtract, lib, "RectangleSubtract")
212		if ret := RectangleSubtract(Rect{15, 5, 3, 7}); ret != expectedDouble {
213			t.Fatalf("RectangleSubtract returned %f wanted %f", ret, expectedDouble)
214		}
215		var Rectangle func(rect Rect) float64
216		purego.RegisterLibFunc(&Rectangle, lib, "Rectangle")
217		if ret := Rectangle(Rect{1, 2, 3, 4}); ret != expectedDouble {
218			t.Fatalf("Rectangle returned %f wanted %f", ret, expectedFloat)
219		}
220	}
221	{
222		type FloatArray struct {
223			a [2]float64
224		}
225		var FloatArrayFn func(rect FloatArray) float64
226		purego.RegisterLibFunc(&FloatArrayFn, lib, "FloatArray")
227		if ret := FloatArrayFn(FloatArray{a: [2]float64{3, 7}}); ret != expectedDouble {
228			t.Fatalf("FloatArray returned %f wanted %f", ret, expectedFloat)
229		}
230	}
231	{
232		type UnsignedChar4Bytes struct {
233			a, b, c, d byte
234		}
235		var UnsignedChar4BytesFn func(UnsignedChar4Bytes) uint32
236		purego.RegisterLibFunc(&UnsignedChar4BytesFn, lib, "UnsignedChar4Bytes")
237		if ret := UnsignedChar4BytesFn(UnsignedChar4Bytes{a: 0xDE, b: 0xAD, c: 0xBE, d: 0xEF}); ret != expectedUnsigned {
238			t.Fatalf("UnsignedChar4BytesFn returned %#x wanted %#x", ret, expectedUnsigned)
239		}
240	}
241	{
242		type UnsignedChar4BytesStruct struct {
243			x struct {
244				a byte
245			}
246			y struct {
247				b byte
248			}
249			z struct {
250				c byte
251			}
252			w struct {
253				d byte
254			}
255		}
256		var UnsignedChar4BytesStructFn func(UnsignedChar4BytesStruct) uint32
257		purego.RegisterLibFunc(&UnsignedChar4BytesStructFn, lib, "UnsignedChar4BytesStruct")
258		if ret := UnsignedChar4BytesStructFn(UnsignedChar4BytesStruct{
259			x: struct{ a byte }{a: 0xDE},
260			y: struct{ b byte }{b: 0xAD},
261			z: struct{ c byte }{c: 0xBE},
262			w: struct{ d byte }{d: 0xEF},
263		}); ret != expectedUnsigned {
264			t.Fatalf("UnsignedChar4BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned)
265		}
266	}
267	{
268		type Short struct {
269			a, b, c, d uint16
270		}
271		var ShortFn func(Short) uint64
272		purego.RegisterLibFunc(&ShortFn, lib, "Short")
273		if ret := ShortFn(Short{a: 0xDEAD, b: 0xBEEF, c: 0xCAFE, d: 0xBABE}); ret != expectedLong {
274			t.Fatalf("ShortFn returned %#x wanted %#x", ret, expectedLong)
275		}
276	}
277	{
278		type Int struct {
279			a, b uint32
280		}
281		var IntFn func(Int) uint64
282		purego.RegisterLibFunc(&IntFn, lib, "Int")
283		if ret := IntFn(Int{a: 0xDEADBEEF, b: 0xCAFEBABE}); ret != expectedLong {
284			t.Fatalf("IntFn returned %#x wanted %#x", ret, expectedLong)
285		}
286	}
287	{
288		type Long struct {
289			a uint64
290		}
291		var LongFn func(Long) uint64
292		purego.RegisterLibFunc(&LongFn, lib, "Long")
293		if ret := LongFn(Long{a: 0xDEADBEEFCAFEBABE}); ret != expectedLong {
294			t.Fatalf("LongFn returned %#x wanted %#x", ret, expectedLong)
295		}
296	}
297	{
298		type Char8Bytes struct {
299			a, b, c, d, e, f, g, h int8
300		}
301		var Char8BytesFn func(Char8Bytes) int32
302		purego.RegisterLibFunc(&Char8BytesFn, lib, "Char8Bytes")
303		if ret := Char8BytesFn(Char8Bytes{a: -128, b: 127, c: 3, d: -88, e: -3, f: 34, g: -48, h: -20}); ret != expectedSigned {
304			t.Fatalf("Char8Bytes returned %d wanted %d", ret, expectedSigned)
305		}
306	}
307	{
308		type Odd struct {
309			a, b, c byte
310		}
311		var OddFn func(Odd) int32
312		purego.RegisterLibFunc(&OddFn, lib, "Odd")
313		if ret := OddFn(Odd{a: 12, b: 23, c: 46}); ret != expectedOdd {
314			t.Fatalf("OddFn returned %d wanted %d", ret, expectedOdd)
315		}
316	}
317	{
318		type Char2Short1 struct {
319			a, b byte
320			c    uint16
321		}
322		var Char2Short1s func(Char2Short1) int32
323		purego.RegisterLibFunc(&Char2Short1s, lib, "Char2Short1s")
324		if ret := Char2Short1s(Char2Short1{a: 12, b: 23, c: 46}); ret != expectedOdd {
325			t.Fatalf("Char2Short1s returned %d wanted %d", ret, expectedOdd)
326		}
327	}
328	{
329		type SignedChar2Short1 struct {
330			a, b int8
331			c    int16
332		}
333		var SignedChar2Short1Fn func(SignedChar2Short1) int32
334		purego.RegisterLibFunc(&SignedChar2Short1Fn, lib, "SignedChar2Short1")
335		if ret := SignedChar2Short1Fn(SignedChar2Short1{a: 100, b: -23, c: -200}); ret != expectedSigned {
336			t.Fatalf("SignedChar2Short1Fn returned %d wanted %d", ret, expectedSigned)
337		}
338	}
339	{
340		type Array4UnsignedChars struct {
341			a [4]uint8
342		}
343		var Array4UnsignedCharsFn func(chars Array4UnsignedChars) uint32
344		purego.RegisterLibFunc(&Array4UnsignedCharsFn, lib, "Array4UnsignedChars")
345		if ret := Array4UnsignedCharsFn(Array4UnsignedChars{a: [...]uint8{0xDE, 0xAD, 0xBE, 0xEF}}); ret != expectedUnsigned {
346			t.Fatalf("Array4UnsignedCharsFn returned %#x wanted %#x", ret, expectedUnsigned)
347		}
348	}
349	{
350		type Array3UnsignedChar struct {
351			a [3]uint8
352		}
353		var Array3UnsignedChars func(chars Array3UnsignedChar) uint32
354		purego.RegisterLibFunc(&Array3UnsignedChars, lib, "Array3UnsignedChars")
355		if ret := Array3UnsignedChars(Array3UnsignedChar{a: [...]uint8{0xDE, 0xAD, 0xBE}}); ret != expectedUnsigned {
356			t.Fatalf("Array4UnsignedCharsFn returned %#x wanted %#x", ret, expectedUnsigned)
357		}
358	}
359	{
360		type Array2UnsignedShort struct {
361			a [2]uint16
362		}
363		var Array2UnsignedShorts func(chars Array2UnsignedShort) uint32
364		purego.RegisterLibFunc(&Array2UnsignedShorts, lib, "Array2UnsignedShorts")
365		if ret := Array2UnsignedShorts(Array2UnsignedShort{a: [...]uint16{0xDEAD, 0xBEEF}}); ret != expectedUnsigned {
366			t.Fatalf("Array4UnsignedCharsFn returned %#x wanted %#x", ret, expectedUnsigned)
367		}
368	}
369	{
370		type Array4Chars struct {
371			a [4]int8
372		}
373		var Array4CharsFn func(chars Array4Chars) int32
374		purego.RegisterLibFunc(&Array4CharsFn, lib, "Array4Chars")
375		if ret := Array4CharsFn(Array4Chars{a: [...]int8{100, -127, 4, -100}}); ret != expectedSigned {
376			t.Fatalf("Array4CharsFn returned %#x wanted %#x", ret, expectedSigned)
377		}
378	}
379	{
380		type Array2Short struct {
381			a [2]int16
382		}
383		var Array2Shorts func(chars Array2Short) int32
384		purego.RegisterLibFunc(&Array2Shorts, lib, "Array2Shorts")
385		if ret := Array2Shorts(Array2Short{a: [...]int16{-333, 210}}); ret != expectedSigned {
386			t.Fatalf("Array4Shorts returned %#x wanted %#x", ret, expectedSigned)
387		}
388	}
389	{
390		type Array3Short struct {
391			a [3]int16
392		}
393		var Array3Shorts func(chars Array3Short) int32
394		purego.RegisterLibFunc(&Array3Shorts, lib, "Array3Shorts")
395		if ret := Array3Shorts(Array3Short{a: [...]int16{-333, 100, 110}}); ret != expectedSigned {
396			t.Fatalf("Array4Shorts returned %#x wanted %#x", ret, expectedSigned)
397		}
398	}
399	{
400		type BoolStruct struct {
401			b bool
402		}
403		var BoolStructFn func(BoolStruct) bool
404		purego.RegisterLibFunc(&BoolStructFn, lib, "BoolStruct")
405		if ret := BoolStructFn(BoolStruct{true}); ret != true {
406			t.Fatalf("BoolStructFn returned %v wanted %v", ret, true)
407		}
408		if ret := BoolStructFn(BoolStruct{false}); ret != false {
409			t.Fatalf("BoolStructFn returned %v wanted %v", ret, false)
410		}
411	}
412	{
413		type BoolFloat struct {
414			b bool
415			_ [3]byte // purego won't do padding for you so make sure it aligns properly with C struct
416			f float32
417		}
418		var BoolFloatFn func(BoolFloat) float32
419		purego.RegisterLibFunc(&BoolFloatFn, lib, "BoolFloat")
420		if ret := BoolFloatFn(BoolFloat{b: true, f: 10}); ret != expectedFloat {
421			t.Fatalf("BoolFloatFn returned %f wanted %f", ret, expectedFloat)
422		}
423		if ret := BoolFloatFn(BoolFloat{b: false, f: 10}); ret != -expectedFloat {
424			t.Fatalf("BoolFloatFn returned %f wanted %f", ret, -expectedFloat)
425		}
426	}
427	{
428		type point struct{ x, y float64 }
429		type size struct{ width, height float64 }
430		type Content struct {
431			point point
432			size  size
433		}
434		var InitWithContentRect func(*int, Content, int32, int32, bool) uint64
435		purego.RegisterLibFunc(&InitWithContentRect, lib, "InitWithContentRect")
436		if ret := InitWithContentRect(new(int),
437			// These numbers are created so that when added together and then divided by 11 it produces 0xdeadbeef
438			Content{point{x: 41_000_000_000, y: 95_000_000}, size{width: 214_000, height: 149}},
439			15, 4, true); ret != expectedUnsigned {
440			t.Fatalf("InitWithContentRect returned %d wanted %#x", ret, expectedUnsigned)
441		}
442	}
443}
444
445func TestRegisterFunc_structReturns(t *testing.T) {
446	libFileName := filepath.Join(t.TempDir(), "structreturntest.so")
447	t.Logf("Build %v", libFileName)
448
449	if err := buildSharedLib("CC", libFileName, filepath.Join("testdata", "structtest", "structreturn_test.c")); err != nil {
450		t.Fatal(err)
451	}
452	defer os.Remove(libFileName)
453
454	lib, err := purego.Dlopen(libFileName, purego.RTLD_NOW|purego.RTLD_GLOBAL)
455	if err != nil {
456		t.Fatalf("Dlopen(%q) failed: %v", libFileName, err)
457	}
458
459	{
460		type Empty struct{}
461		var ReturnEmpty func() Empty
462		purego.RegisterLibFunc(&ReturnEmpty, lib, "ReturnEmpty")
463		ret := ReturnEmpty()
464		_ = ret
465	}
466	{
467		type inner struct{ a int16 }
468		type StructInStruct struct {
469			a inner
470			b inner
471			c inner
472		}
473		var ReturnStructInStruct func(a, b, c int16) StructInStruct
474		purego.RegisterLibFunc(&ReturnStructInStruct, lib, "ReturnStructInStruct")
475		expected := StructInStruct{inner{^int16(0)}, inner{2}, inner{3}}
476		if ret := ReturnStructInStruct(^int16(0), 2, 3); ret != expected {
477			t.Fatalf("StructInStruct returned %+v wanted %+v", ret, expected)
478		}
479	}
480	{
481		type ThreeShorts struct{ a, b, c int16 }
482		var ReturnThreeShorts func(a, b, c int16) ThreeShorts
483		purego.RegisterLibFunc(&ReturnThreeShorts, lib, "ReturnThreeShorts")
484		expected := ThreeShorts{^int16(0), 2, 3}
485		if ret := ReturnThreeShorts(^int16(0), 2, 3); ret != expected {
486			t.Fatalf("ReturnThreeShorts returned %+v wanted %+v", ret, expected)
487		}
488	}
489	{
490		type FourShorts struct{ a, b, c, d int16 }
491		var ReturnFourShorts func(a, b, c, d int16) FourShorts
492		purego.RegisterLibFunc(&ReturnFourShorts, lib, "ReturnFourShorts")
493		expected := FourShorts{^int16(0), 2, 3, 4}
494		if ret := ReturnFourShorts(^int16(0), 2, 3, 4); ret != expected {
495			t.Fatalf("ReturnFourShorts returned %+v wanted %+v", ret, expected)
496		}
497	}
498	{
499		type OneLong struct{ a int64 }
500		var ReturnOneLong func(a int64) OneLong
501		purego.RegisterLibFunc(&ReturnOneLong, lib, "ReturnOneLong")
502		expected := OneLong{5}
503		if ret := ReturnOneLong(5); ret != expected {
504			t.Fatalf("ReturnOneLong returned %+v wanted %+v", ret, expected)
505		}
506	}
507	{
508		type TwoLongs struct{ a, b int64 }
509		var ReturnTwoLongs func(a, b int64) TwoLongs
510		purego.RegisterLibFunc(&ReturnTwoLongs, lib, "ReturnTwoLongs")
511		expected := TwoLongs{1, 2}
512		if ret := ReturnTwoLongs(1, 2); ret != expected {
513			t.Fatalf("ReturnTwoLongs returned %+v wanted %+v", ret, expected)
514		}
515	}
516	{
517		type ThreeLongs struct{ a, b, c int64 }
518		var ReturnThreeLongs func(a, b, c int64) ThreeLongs
519		purego.RegisterLibFunc(&ReturnThreeLongs, lib, "ReturnThreeLongs")
520		expected := ThreeLongs{1, 2, 3}
521		if ret := ReturnThreeLongs(1, 2, 3); ret != expected {
522			t.Fatalf("ReturnThreeLongs returned %+v wanted %+v", ret, expected)
523		}
524	}
525	{
526		type OneFloat struct{ a float32 }
527		var ReturnOneFloat func(a float32) OneFloat
528		purego.RegisterLibFunc(&ReturnOneFloat, lib, "ReturnOneFloat")
529		expected := OneFloat{1}
530		if ret := ReturnOneFloat(1); ret != expected {
531			t.Fatalf("ReturnOneFloat returned %+v wanted %+v", ret, expected)
532		}
533	}
534	{
535		type TwoFloats struct{ a, b float32 }
536		var ReturnTwoFloats func(a, b float32) TwoFloats
537		purego.RegisterLibFunc(&ReturnTwoFloats, lib, "ReturnTwoFloats")
538		expected := TwoFloats{3, 10}
539		if ret := ReturnTwoFloats(5, 2); ret != expected {
540			t.Fatalf("ReturnTwoFloats returned %+v wanted %+v", ret, expected)
541		}
542	}
543	{
544		type ThreeFloats struct{ a, b, c float32 }
545		var ReturnThreeFloats func(a, b, c float32) ThreeFloats
546		purego.RegisterLibFunc(&ReturnThreeFloats, lib, "ReturnThreeFloats")
547		expected := ThreeFloats{1, 2, 3}
548		if ret := ReturnThreeFloats(1, 2, 3); ret != expected {
549			t.Fatalf("ReturnThreeFloats returned %+v wanted %+v", ret, expected)
550		}
551	}
552	{
553		type OneDouble struct{ a float64 }
554		var ReturnOneDouble func(a float64) OneDouble
555		purego.RegisterLibFunc(&ReturnOneDouble, lib, "ReturnOneDouble")
556		expected := OneDouble{1}
557		if ret := ReturnOneDouble(1); ret != expected {
558			t.Fatalf("ReturnOneDouble returned %+v wanted %+v", ret, expected)
559		}
560	}
561	{
562		type TwoDoubles struct{ a, b float64 }
563		var ReturnTwoDoubles func(a, b float64) TwoDoubles
564		purego.RegisterLibFunc(&ReturnTwoDoubles, lib, "ReturnTwoDoubles")
565		expected := TwoDoubles{1, 2}
566		if ret := ReturnTwoDoubles(1, 2); ret != expected {
567			t.Fatalf("ReturnTwoDoubles returned %+v wanted %+v", ret, expected)
568		}
569	}
570	{
571		type ThreeDoubles struct{ a, b, c float64 }
572		var ReturnThreeDoubles func(a, b, c float64) ThreeDoubles
573		purego.RegisterLibFunc(&ReturnThreeDoubles, lib, "ReturnThreeDoubles")
574		expected := ThreeDoubles{1, 2, 3}
575		if ret := ReturnThreeDoubles(1, 2, 3); ret != expected {
576			t.Fatalf("ReturnThreeDoubles returned %+v wanted %+v", ret, expected)
577		}
578	}
579	{
580		type FourDoubles struct{ a, b, c, d float64 }
581		var ReturnFourDoubles func(a, b, c, d float64) FourDoubles
582		purego.RegisterLibFunc(&ReturnFourDoubles, lib, "ReturnFourDoubles")
583		expected := FourDoubles{1, 2, 3, 4}
584		if ret := ReturnFourDoubles(1, 2, 3, 4); ret != expected {
585			t.Fatalf("ReturnFourDoubles returned %+v wanted %+v", ret, expected)
586		}
587	}
588	{
589		type FiveDoubles struct{ a, b, c, d, e float64 }
590		var ReturnFiveDoubles func(a, b, c, d, e float64) FiveDoubles
591		purego.RegisterLibFunc(&ReturnFiveDoubles, lib, "ReturnFiveDoubles")
592		expected := FiveDoubles{1, 2, 3, 4, 5}
593		if ret := ReturnFiveDoubles(1, 2, 3, 4, 5); ret != expected {
594			t.Fatalf("ReturnFiveDoubles returned %+v wanted %+v", ret, expected)
595		}
596	}
597	{
598		type OneFloatOneDouble struct {
599			a float32
600			_ float32
601			b float64
602		}
603		var ReturnOneFloatOneDouble func(a float32, b float64) OneFloatOneDouble
604		purego.RegisterLibFunc(&ReturnOneFloatOneDouble, lib, "ReturnOneFloatOneDouble")
605		expected := OneFloatOneDouble{a: 1, b: 2}
606		if ret := ReturnOneFloatOneDouble(1, 2); ret != expected {
607			t.Fatalf("ReturnOneFloatOneDouble returned %+v wanted %+v", ret, expected)
608		}
609	}
610	{
611		type OneDoubleOneFloat struct {
612			a float64
613			b float32
614		}
615		var ReturnOneDoubleOneFloat func(a float64, b float32) OneDoubleOneFloat
616		purego.RegisterLibFunc(&ReturnOneDoubleOneFloat, lib, "ReturnOneDoubleOneFloat")
617		expected := OneDoubleOneFloat{1, 2}
618		if ret := ReturnOneDoubleOneFloat(1, 2); ret != expected {
619			t.Fatalf("ReturnOneDoubleOneFloat returned %+v wanted %+v", ret, expected)
620		}
621	}
622	{
623		type Unaligned1 struct {
624			a int8
625			_ [1]int8
626			b int16
627			_ [1]int32
628			c int64
629		}
630		var ReturnUnaligned1 func(a int8, b int16, c int64) Unaligned1
631		purego.RegisterLibFunc(&ReturnUnaligned1, lib, "ReturnUnaligned1")
632		expected := Unaligned1{a: 1, b: 2, c: 3}
633		if ret := ReturnUnaligned1(1, 2, 3); ret != expected {
634			t.Fatalf("ReturnUnaligned1 returned %+v wanted %+v", ret, expected)
635		}
636	}
637	{
638		type Mixed1 struct {
639			a float32
640			b int32
641		}
642		var ReturnMixed1 func(a float32, b int32) Mixed1
643		purego.RegisterLibFunc(&ReturnMixed1, lib, "ReturnMixed1")
644		expected := Mixed1{1, 2}
645		if ret := ReturnMixed1(1, 2); ret != expected {
646			t.Fatalf("ReturnMixed1 returned %+v wanted %+v", ret, expected)
647		}
648	}
649	{
650		type Mixed2 struct {
651			a float32
652			b int32
653			c float32
654			d int32
655		}
656		var ReturnMixed2 func(a float32, b int32, c float32, d int32) Mixed2
657		purego.RegisterLibFunc(&ReturnMixed2, lib, "ReturnMixed2")
658		expected := Mixed2{1, 2, 3, 4}
659		if ret := ReturnMixed2(1, 2, 3, 4); ret != expected {
660			t.Fatalf("ReturnMixed2 returned %+v wanted %+v", ret, expected)
661		}
662	}
663	{
664		type Mixed3 struct {
665			a float32
666			b uint32
667			c float64
668		}
669		var ReturnMixed3 func(a float32, b uint32, c float64) Mixed3
670		purego.RegisterLibFunc(&ReturnMixed3, lib, "ReturnMixed3")
671		expected := Mixed3{1, 2, 3}
672		if ret := ReturnMixed3(1, 2, 3); ret != expected {
673			t.Fatalf("ReturnMixed3 returned %+v wanted %+v", ret, expected)
674		}
675	}
676	{
677		type Mixed4 struct {
678			a float64
679			b uint32
680			c float32
681		}
682		var ReturnMixed4 func(a float64, b uint32, c float32) Mixed4
683		purego.RegisterLibFunc(&ReturnMixed4, lib, "ReturnMixed4")
684		expected := Mixed4{1, 2, 3}
685		if ret := ReturnMixed4(1, 2, 3); ret != expected {
686			t.Fatalf("ReturnMixed4 returned %+v wanted %+v", ret, expected)
687		}
688	}
689	{
690		type Ptr1 struct {
691			a *int64
692			b unsafe.Pointer
693		}
694		var ReturnPtr1 func(a *int64, b unsafe.Pointer) Ptr1
695		purego.RegisterLibFunc(&ReturnPtr1, lib, "ReturnPtr1")
696		a, b := new(int64), new(struct{})
697		expected := Ptr1{a, unsafe.Pointer(b)}
698		if ret := ReturnPtr1(a, unsafe.Pointer(b)); ret != expected {
699			t.Fatalf("ReturnPtr1 returned %+v wanted %+v", ret, expected)
700		}
701		runtime.KeepAlive(a)
702		runtime.KeepAlive(b)
703	}
704}

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