summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-mangler/v2/map.go
blob: 986aca4b04d754bf8cb2dfd0e5455d4e12a78785 (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
76
77
78
79
80
package mangler

import (
	"unsafe"

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

// iterMapType returns a Mangler capable of iterating
// and mangling the given map type currently in TypeIter{}.
// note this will fetch sub-Manglers for key / value types.
func iterMapType(t xunsafe.TypeIter) Mangler {

	// Key / value types.
	key := t.Type.Key()
	elem := t.Type.Elem()

	// Get nested k / v TypeIters with appropriate flags.
	flagsKey := xunsafe.ReflectMapKeyFlags(key)
	flagsVal := xunsafe.ReflectMapElemFlags(elem)
	kt := t.Child(key, flagsKey)
	vt := t.Child(elem, flagsVal)

	// Get key mangler.
	kfn := loadOrGet(kt)
	if kfn == nil {
		return nil
	}

	// Get value mangler.
	vfn := loadOrGet(vt)
	if vfn == nil {
		return nil
	}

	// Final map type.
	rtype := t.Type
	flags := t.Flag

	return func(buf []byte, ptr unsafe.Pointer) []byte {
		if ptr == nil || *(*unsafe.Pointer)(ptr) == nil {
			// Append nil indicator.
			buf = append(buf, '0')
			return buf
		}

		// Build reflect value, and then a map iterator.
		v := xunsafe.BuildReflectValue(rtype, ptr, flags)
		i := xunsafe.GetMapIter(v)

		// Before len.
		l := len(buf)

		// Append not-nil flag.
		buf = append(buf, '1')

		for i.Next() {
			// Pass to map key func.
			ptr = xunsafe.Map_Key(i)
			buf = kfn(buf, ptr)

			// Add key seperator.
			buf = append(buf, ':')

			// Pass to map elem func.
			ptr = xunsafe.Map_Elem(i)
			buf = vfn(buf, ptr)

			// Add comma seperator.
			buf = append(buf, ',')
		}

		if len(buf) != l {
			// Drop final comma.
			buf = buf[:len(buf)-1]
		}

		return buf
	}
}