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