summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-mangler/v2/struct.go
blob: e9672bf2b0c13381abecdccd2aae8bd9132c453e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package mangler

import (
	"unsafe"

	"codeberg.org/gruf/go-xunsafe"
)

// field stores the minimum necessary
// data for iterating and mangling
// each field in a given struct.
type field struct {
	mangle Mangler
	offset uintptr
}

// iterStructType returns a Mangler capable of iterating
// and mangling the given struct type currently in TypeIter{}.
// note this will fetch sub-Manglers for each struct field.
func iterStructType(t xunsafe.TypeIter) Mangler {

	// Number of struct fields.
	n := t.Type.NumField()

	// Gather mangler functions.
	fields := make([]field, n)
	for i := 0; i < n; i++ {

		// Get struct field at index.
		sfield := t.Type.Field(i)
		rtype := sfield.Type

		// Get nested field TypeIter with appropriate flags.
		flags := xunsafe.ReflectStructFieldFlags(t.Flag, rtype)
		ft := t.Child(sfield.Type, flags)

		// Get field mangler.
		fn := loadOrGet(ft)
		if fn == nil {
			return nil
		}

		// Set field info.
		fields[i] = field{
			mangle: fn,
			offset: sfield.Offset,
		}
	}

	// Handle no. fields.
	switch len(fields) {
	case 0:
		return empty_mangler
	case 1:
		return fields[0].mangle
	default:
		return func(buf []byte, ptr unsafe.Pointer) []byte {
			for i := range fields {
				// Get struct field ptr via offset.
				fptr := add(ptr, fields[i].offset)

				// Mangle the struct field data.
				buf = fields[i].mangle(buf, fptr)
				buf = append(buf, ',')
			}

			if len(fields) > 0 {
				// Drop final comma.
				buf = buf[:len(buf)-1]
			}

			return buf
		}
	}
}