xref: /aosp_15_r20/external/golang-protobuf/reflect/protopath/step.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2020 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsenpackage protopath
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"fmt"
9*1c12ee1eSDan Willemsen	"strconv"
10*1c12ee1eSDan Willemsen	"strings"
11*1c12ee1eSDan Willemsen
12*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/encoding/text"
13*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
14*1c12ee1eSDan Willemsen)
15*1c12ee1eSDan Willemsen
16*1c12ee1eSDan Willemsen// StepKind identifies the kind of step operation.
17*1c12ee1eSDan Willemsen// Each kind of step corresponds with some protobuf reflection operation.
18*1c12ee1eSDan Willemsentype StepKind int
19*1c12ee1eSDan Willemsen
20*1c12ee1eSDan Willemsenconst (
21*1c12ee1eSDan Willemsen	invalidStep StepKind = iota
22*1c12ee1eSDan Willemsen	// RootStep identifies a step as the Root step operation.
23*1c12ee1eSDan Willemsen	RootStep
24*1c12ee1eSDan Willemsen	// FieldAccessStep identifies a step as the FieldAccess step operation.
25*1c12ee1eSDan Willemsen	FieldAccessStep
26*1c12ee1eSDan Willemsen	// UnknownAccessStep identifies a step as the UnknownAccess step operation.
27*1c12ee1eSDan Willemsen	UnknownAccessStep
28*1c12ee1eSDan Willemsen	// ListIndexStep identifies a step as the ListIndex step operation.
29*1c12ee1eSDan Willemsen	ListIndexStep
30*1c12ee1eSDan Willemsen	// MapIndexStep identifies a step as the MapIndex step operation.
31*1c12ee1eSDan Willemsen	MapIndexStep
32*1c12ee1eSDan Willemsen	// AnyExpandStep identifies a step as the AnyExpand step operation.
33*1c12ee1eSDan Willemsen	AnyExpandStep
34*1c12ee1eSDan Willemsen)
35*1c12ee1eSDan Willemsen
36*1c12ee1eSDan Willemsenfunc (k StepKind) String() string {
37*1c12ee1eSDan Willemsen	switch k {
38*1c12ee1eSDan Willemsen	case invalidStep:
39*1c12ee1eSDan Willemsen		return "<invalid>"
40*1c12ee1eSDan Willemsen	case RootStep:
41*1c12ee1eSDan Willemsen		return "Root"
42*1c12ee1eSDan Willemsen	case FieldAccessStep:
43*1c12ee1eSDan Willemsen		return "FieldAccess"
44*1c12ee1eSDan Willemsen	case UnknownAccessStep:
45*1c12ee1eSDan Willemsen		return "UnknownAccess"
46*1c12ee1eSDan Willemsen	case ListIndexStep:
47*1c12ee1eSDan Willemsen		return "ListIndex"
48*1c12ee1eSDan Willemsen	case MapIndexStep:
49*1c12ee1eSDan Willemsen		return "MapIndex"
50*1c12ee1eSDan Willemsen	case AnyExpandStep:
51*1c12ee1eSDan Willemsen		return "AnyExpand"
52*1c12ee1eSDan Willemsen	default:
53*1c12ee1eSDan Willemsen		return fmt.Sprintf("<unknown:%d>", k)
54*1c12ee1eSDan Willemsen	}
55*1c12ee1eSDan Willemsen}
56*1c12ee1eSDan Willemsen
57*1c12ee1eSDan Willemsen// Step is a union where only one step operation may be specified at a time.
58*1c12ee1eSDan Willemsen// The different kinds of steps are specified by the constants defined for
59*1c12ee1eSDan Willemsen// the StepKind type.
60*1c12ee1eSDan Willemsentype Step struct {
61*1c12ee1eSDan Willemsen	kind StepKind
62*1c12ee1eSDan Willemsen	desc protoreflect.Descriptor
63*1c12ee1eSDan Willemsen	key  protoreflect.Value
64*1c12ee1eSDan Willemsen}
65*1c12ee1eSDan Willemsen
66*1c12ee1eSDan Willemsen// Root indicates the root message that a path is relative to.
67*1c12ee1eSDan Willemsen// It should always (and only ever) be the first step in a path.
68*1c12ee1eSDan Willemsenfunc Root(md protoreflect.MessageDescriptor) Step {
69*1c12ee1eSDan Willemsen	if md == nil {
70*1c12ee1eSDan Willemsen		panic("nil message descriptor")
71*1c12ee1eSDan Willemsen	}
72*1c12ee1eSDan Willemsen	return Step{kind: RootStep, desc: md}
73*1c12ee1eSDan Willemsen}
74*1c12ee1eSDan Willemsen
75*1c12ee1eSDan Willemsen// FieldAccess describes access of a field within a message.
76*1c12ee1eSDan Willemsen// Extension field accesses are also represented using a FieldAccess and
77*1c12ee1eSDan Willemsen// must be provided with a protoreflect.FieldDescriptor
78*1c12ee1eSDan Willemsen//
79*1c12ee1eSDan Willemsen// Within the context of Values,
80*1c12ee1eSDan Willemsen// the type of the previous step value is always a message, and
81*1c12ee1eSDan Willemsen// the type of the current step value is determined by the field descriptor.
82*1c12ee1eSDan Willemsenfunc FieldAccess(fd protoreflect.FieldDescriptor) Step {
83*1c12ee1eSDan Willemsen	if fd == nil {
84*1c12ee1eSDan Willemsen		panic("nil field descriptor")
85*1c12ee1eSDan Willemsen	} else if _, ok := fd.(protoreflect.ExtensionTypeDescriptor); !ok && fd.IsExtension() {
86*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("extension field %q must implement protoreflect.ExtensionTypeDescriptor", fd.FullName()))
87*1c12ee1eSDan Willemsen	}
88*1c12ee1eSDan Willemsen	return Step{kind: FieldAccessStep, desc: fd}
89*1c12ee1eSDan Willemsen}
90*1c12ee1eSDan Willemsen
91*1c12ee1eSDan Willemsen// UnknownAccess describes access to the unknown fields within a message.
92*1c12ee1eSDan Willemsen//
93*1c12ee1eSDan Willemsen// Within the context of Values,
94*1c12ee1eSDan Willemsen// the type of the previous step value is always a message, and
95*1c12ee1eSDan Willemsen// the type of the current step value is always a bytes type.
96*1c12ee1eSDan Willemsenfunc UnknownAccess() Step {
97*1c12ee1eSDan Willemsen	return Step{kind: UnknownAccessStep}
98*1c12ee1eSDan Willemsen}
99*1c12ee1eSDan Willemsen
100*1c12ee1eSDan Willemsen// ListIndex describes index of an element within a list.
101*1c12ee1eSDan Willemsen//
102*1c12ee1eSDan Willemsen// Within the context of Values,
103*1c12ee1eSDan Willemsen// the type of the previous, previous step value is always a message,
104*1c12ee1eSDan Willemsen// the type of the previous step value is always a list, and
105*1c12ee1eSDan Willemsen// the type of the current step value is determined by the field descriptor.
106*1c12ee1eSDan Willemsenfunc ListIndex(i int) Step {
107*1c12ee1eSDan Willemsen	if i < 0 {
108*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("invalid list index: %v", i))
109*1c12ee1eSDan Willemsen	}
110*1c12ee1eSDan Willemsen	return Step{kind: ListIndexStep, key: protoreflect.ValueOfInt64(int64(i))}
111*1c12ee1eSDan Willemsen}
112*1c12ee1eSDan Willemsen
113*1c12ee1eSDan Willemsen// MapIndex describes index of an entry within a map.
114*1c12ee1eSDan Willemsen// The key type is determined by field descriptor that the map belongs to.
115*1c12ee1eSDan Willemsen//
116*1c12ee1eSDan Willemsen// Within the context of Values,
117*1c12ee1eSDan Willemsen// the type of the previous previous step value is always a message,
118*1c12ee1eSDan Willemsen// the type of the previous step value is always a map, and
119*1c12ee1eSDan Willemsen// the type of the current step value is determined by the field descriptor.
120*1c12ee1eSDan Willemsenfunc MapIndex(k protoreflect.MapKey) Step {
121*1c12ee1eSDan Willemsen	if !k.IsValid() {
122*1c12ee1eSDan Willemsen		panic("invalid map index")
123*1c12ee1eSDan Willemsen	}
124*1c12ee1eSDan Willemsen	return Step{kind: MapIndexStep, key: k.Value()}
125*1c12ee1eSDan Willemsen}
126*1c12ee1eSDan Willemsen
127*1c12ee1eSDan Willemsen// AnyExpand describes expansion of a google.protobuf.Any message into
128*1c12ee1eSDan Willemsen// a structured representation of the underlying message.
129*1c12ee1eSDan Willemsen//
130*1c12ee1eSDan Willemsen// Within the context of Values,
131*1c12ee1eSDan Willemsen// the type of the previous step value is always a google.protobuf.Any message, and
132*1c12ee1eSDan Willemsen// the type of the current step value is always a message.
133*1c12ee1eSDan Willemsenfunc AnyExpand(md protoreflect.MessageDescriptor) Step {
134*1c12ee1eSDan Willemsen	if md == nil {
135*1c12ee1eSDan Willemsen		panic("nil message descriptor")
136*1c12ee1eSDan Willemsen	}
137*1c12ee1eSDan Willemsen	return Step{kind: AnyExpandStep, desc: md}
138*1c12ee1eSDan Willemsen}
139*1c12ee1eSDan Willemsen
140*1c12ee1eSDan Willemsen// MessageDescriptor returns the message descriptor for Root or AnyExpand steps,
141*1c12ee1eSDan Willemsen// otherwise it returns nil.
142*1c12ee1eSDan Willemsenfunc (s Step) MessageDescriptor() protoreflect.MessageDescriptor {
143*1c12ee1eSDan Willemsen	switch s.kind {
144*1c12ee1eSDan Willemsen	case RootStep, AnyExpandStep:
145*1c12ee1eSDan Willemsen		return s.desc.(protoreflect.MessageDescriptor)
146*1c12ee1eSDan Willemsen	default:
147*1c12ee1eSDan Willemsen		return nil
148*1c12ee1eSDan Willemsen	}
149*1c12ee1eSDan Willemsen}
150*1c12ee1eSDan Willemsen
151*1c12ee1eSDan Willemsen// FieldDescriptor returns the field descriptor for FieldAccess steps,
152*1c12ee1eSDan Willemsen// otherwise it returns nil.
153*1c12ee1eSDan Willemsenfunc (s Step) FieldDescriptor() protoreflect.FieldDescriptor {
154*1c12ee1eSDan Willemsen	switch s.kind {
155*1c12ee1eSDan Willemsen	case FieldAccessStep:
156*1c12ee1eSDan Willemsen		return s.desc.(protoreflect.FieldDescriptor)
157*1c12ee1eSDan Willemsen	default:
158*1c12ee1eSDan Willemsen		return nil
159*1c12ee1eSDan Willemsen	}
160*1c12ee1eSDan Willemsen}
161*1c12ee1eSDan Willemsen
162*1c12ee1eSDan Willemsen// ListIndex returns the list index for ListIndex steps,
163*1c12ee1eSDan Willemsen// otherwise it returns 0.
164*1c12ee1eSDan Willemsenfunc (s Step) ListIndex() int {
165*1c12ee1eSDan Willemsen	switch s.kind {
166*1c12ee1eSDan Willemsen	case ListIndexStep:
167*1c12ee1eSDan Willemsen		return int(s.key.Int())
168*1c12ee1eSDan Willemsen	default:
169*1c12ee1eSDan Willemsen		return 0
170*1c12ee1eSDan Willemsen	}
171*1c12ee1eSDan Willemsen}
172*1c12ee1eSDan Willemsen
173*1c12ee1eSDan Willemsen// MapIndex returns the map key for MapIndex steps,
174*1c12ee1eSDan Willemsen// otherwise it returns an invalid map key.
175*1c12ee1eSDan Willemsenfunc (s Step) MapIndex() protoreflect.MapKey {
176*1c12ee1eSDan Willemsen	switch s.kind {
177*1c12ee1eSDan Willemsen	case MapIndexStep:
178*1c12ee1eSDan Willemsen		return s.key.MapKey()
179*1c12ee1eSDan Willemsen	default:
180*1c12ee1eSDan Willemsen		return protoreflect.MapKey{}
181*1c12ee1eSDan Willemsen	}
182*1c12ee1eSDan Willemsen}
183*1c12ee1eSDan Willemsen
184*1c12ee1eSDan Willemsen// Kind reports which kind of step this is.
185*1c12ee1eSDan Willemsenfunc (s Step) Kind() StepKind {
186*1c12ee1eSDan Willemsen	return s.kind
187*1c12ee1eSDan Willemsen}
188*1c12ee1eSDan Willemsen
189*1c12ee1eSDan Willemsenfunc (s Step) String() string {
190*1c12ee1eSDan Willemsen	return string(s.appendString(nil))
191*1c12ee1eSDan Willemsen}
192*1c12ee1eSDan Willemsen
193*1c12ee1eSDan Willemsenfunc (s Step) appendString(b []byte) []byte {
194*1c12ee1eSDan Willemsen	switch s.kind {
195*1c12ee1eSDan Willemsen	case RootStep:
196*1c12ee1eSDan Willemsen		b = append(b, '(')
197*1c12ee1eSDan Willemsen		b = append(b, s.desc.FullName()...)
198*1c12ee1eSDan Willemsen		b = append(b, ')')
199*1c12ee1eSDan Willemsen	case FieldAccessStep:
200*1c12ee1eSDan Willemsen		b = append(b, '.')
201*1c12ee1eSDan Willemsen		if fd := s.desc.(protoreflect.FieldDescriptor); fd.IsExtension() {
202*1c12ee1eSDan Willemsen			b = append(b, '(')
203*1c12ee1eSDan Willemsen			b = append(b, strings.Trim(fd.TextName(), "[]")...)
204*1c12ee1eSDan Willemsen			b = append(b, ')')
205*1c12ee1eSDan Willemsen		} else {
206*1c12ee1eSDan Willemsen			b = append(b, fd.TextName()...)
207*1c12ee1eSDan Willemsen		}
208*1c12ee1eSDan Willemsen	case UnknownAccessStep:
209*1c12ee1eSDan Willemsen		b = append(b, '.')
210*1c12ee1eSDan Willemsen		b = append(b, '?')
211*1c12ee1eSDan Willemsen	case ListIndexStep:
212*1c12ee1eSDan Willemsen		b = append(b, '[')
213*1c12ee1eSDan Willemsen		b = strconv.AppendInt(b, s.key.Int(), 10)
214*1c12ee1eSDan Willemsen		b = append(b, ']')
215*1c12ee1eSDan Willemsen	case MapIndexStep:
216*1c12ee1eSDan Willemsen		b = append(b, '[')
217*1c12ee1eSDan Willemsen		switch k := s.key.Interface().(type) {
218*1c12ee1eSDan Willemsen		case bool:
219*1c12ee1eSDan Willemsen			b = strconv.AppendBool(b, bool(k)) // e.g., "true" or "false"
220*1c12ee1eSDan Willemsen		case int32:
221*1c12ee1eSDan Willemsen			b = strconv.AppendInt(b, int64(k), 10) // e.g., "-32"
222*1c12ee1eSDan Willemsen		case int64:
223*1c12ee1eSDan Willemsen			b = strconv.AppendInt(b, int64(k), 10) // e.g., "-64"
224*1c12ee1eSDan Willemsen		case uint32:
225*1c12ee1eSDan Willemsen			b = strconv.AppendUint(b, uint64(k), 10) // e.g., "32"
226*1c12ee1eSDan Willemsen		case uint64:
227*1c12ee1eSDan Willemsen			b = strconv.AppendUint(b, uint64(k), 10) // e.g., "64"
228*1c12ee1eSDan Willemsen		case string:
229*1c12ee1eSDan Willemsen			b = text.AppendString(b, k) // e.g., `"hello, world"`
230*1c12ee1eSDan Willemsen		}
231*1c12ee1eSDan Willemsen		b = append(b, ']')
232*1c12ee1eSDan Willemsen	case AnyExpandStep:
233*1c12ee1eSDan Willemsen		b = append(b, '.')
234*1c12ee1eSDan Willemsen		b = append(b, '(')
235*1c12ee1eSDan Willemsen		b = append(b, s.desc.FullName()...)
236*1c12ee1eSDan Willemsen		b = append(b, ')')
237*1c12ee1eSDan Willemsen	default:
238*1c12ee1eSDan Willemsen		b = append(b, "<invalid>"...)
239*1c12ee1eSDan Willemsen	}
240*1c12ee1eSDan Willemsen	return b
241*1c12ee1eSDan Willemsen}
242