summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-kv/v2/format/pointer.go
blob: ec1e2e15da5c6a59f3a5bd75271483b9ce0c2e05 (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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package format

import (
	"reflect"
	"unsafe"

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

// derefPointerType returns a FormatFunc capable of dereferencing
// and formatting the given pointer type currently in TypeIter{}.
// note this will fetch a sub-FormatFunc for resulting value type.
func (fmt *Formatter) derefPointerType(t xunsafe.TypeIter) FormatFunc {
	var n int
	rtype := t.Type
	flags := t.Flag

	// Iteratively dereference pointer types.
	for rtype.Kind() == reflect.Pointer {

		// If this actual indirect memory,
		// increase dereferences counter.
		if flags&xunsafe.Reflect_flagIndir != 0 {
			n++
		}

		// Get next elem type.
		rtype = rtype.Elem()

		// Get next set of dereferenced element type flags.
		flags = xunsafe.ReflectPointerElemFlags(flags, rtype)
	}

	// Wrap value as TypeIter.
	vt := t.Child(rtype, flags)

	// Get value format func.
	fn := fmt.loadOrGet(vt)
	if fn == nil {
		panic("unreachable")
	}

	if !needs_typestr(t) {
		if n <= 0 {
			// No derefs are needed.
			return func(s *State) {
				if s.P == nil {
					// Final check.
					appendNil(s)
					return
				}

				// Format
				// final
				// value.
				fn(s)
			}
		}

		return func(s *State) {
			// Deref n number times.
			for i := n; i > 0; i-- {

				if s.P == nil {
					// Nil check.
					appendNil(s)
					return
				}

				// Further deref pointer value.
				s.P = *(*unsafe.Pointer)(s.P)
			}

			if s.P == nil {
				// Final check.
				appendNil(s)
				return
			}

			// Format
			// final
			// value.
			fn(s)
		}
	}

	// Final type string with ptrs.
	typestr := typestr_with_ptrs(t)

	if n <= 0 {
		// No derefs are needed.
		return func(s *State) {
			if s.P == nil {
				// Final nil value check.
				appendNilType(s, typestr)
				return
			}

			// Format
			// final
			// value.
			fn(s)
		}
	}

	return func(s *State) {
		// Deref n number times.
		for i := n; i > 0; i-- {
			if s.P == nil {
				// Check for nil value.
				appendNilType(s, typestr)
				return
			}

			// Further deref pointer value.
			s.P = *(*unsafe.Pointer)(s.P)
		}

		if s.P == nil {
			// Final nil value check.
			appendNilType(s, typestr)
			return
		}

		// Format
		// final
		// value.
		fn(s)
	}
}