summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-kv/v2/format/pointer.go
blob: 1f860aba9adb6bb20fa56c89235d241f09165c49 (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
package format

import (
	"reflect"
	"unsafe"
)

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

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

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

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

		// Get next set of dereferenced elem type flags.
		flags = reflect_pointer_elem_flags(flags, rtype)
	}

	// Wrap value as typenode.
	vt := t.next(rtype, flags)

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

	if !t.needs_typestr() {
		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 := t.typestr_with_ptrs()

	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)
	}
}