123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- // Copyright 2020 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package protopath
- import (
- "fmt"
- "strconv"
- "strings"
- "google.golang.org/protobuf/internal/encoding/text"
- "google.golang.org/protobuf/reflect/protoreflect"
- )
- // StepKind identifies the kind of step operation.
- // Each kind of step corresponds with some protobuf reflection operation.
- type StepKind int
- const (
- invalidStep StepKind = iota
- // RootStep identifies a step as the Root step operation.
- RootStep
- // FieldAccessStep identifies a step as the FieldAccess step operation.
- FieldAccessStep
- // UnknownAccessStep identifies a step as the UnknownAccess step operation.
- UnknownAccessStep
- // ListIndexStep identifies a step as the ListIndex step operation.
- ListIndexStep
- // MapIndexStep identifies a step as the MapIndex step operation.
- MapIndexStep
- // AnyExpandStep identifies a step as the AnyExpand step operation.
- AnyExpandStep
- )
- func (k StepKind) String() string {
- switch k {
- case invalidStep:
- return "<invalid>"
- case RootStep:
- return "Root"
- case FieldAccessStep:
- return "FieldAccess"
- case UnknownAccessStep:
- return "UnknownAccess"
- case ListIndexStep:
- return "ListIndex"
- case MapIndexStep:
- return "MapIndex"
- case AnyExpandStep:
- return "AnyExpand"
- default:
- return fmt.Sprintf("<unknown:%d>", k)
- }
- }
- // Step is a union where only one step operation may be specified at a time.
- // The different kinds of steps are specified by the constants defined for
- // the StepKind type.
- type Step struct {
- kind StepKind
- desc protoreflect.Descriptor
- key protoreflect.Value
- }
- // Root indicates the root message that a path is relative to.
- // It should always (and only ever) be the first step in a path.
- func Root(md protoreflect.MessageDescriptor) Step {
- if md == nil {
- panic("nil message descriptor")
- }
- return Step{kind: RootStep, desc: md}
- }
- // FieldAccess describes access of a field within a message.
- // Extension field accesses are also represented using a FieldAccess and
- // must be provided with a protoreflect.FieldDescriptor
- //
- // Within the context of Values,
- // the type of the previous step value is always a message, and
- // the type of the current step value is determined by the field descriptor.
- func FieldAccess(fd protoreflect.FieldDescriptor) Step {
- if fd == nil {
- panic("nil field descriptor")
- } else if _, ok := fd.(protoreflect.ExtensionTypeDescriptor); !ok && fd.IsExtension() {
- panic(fmt.Sprintf("extension field %q must implement protoreflect.ExtensionTypeDescriptor", fd.FullName()))
- }
- return Step{kind: FieldAccessStep, desc: fd}
- }
- // UnknownAccess describes access to the unknown fields within a message.
- //
- // Within the context of Values,
- // the type of the previous step value is always a message, and
- // the type of the current step value is always a bytes type.
- func UnknownAccess() Step {
- return Step{kind: UnknownAccessStep}
- }
- // ListIndex describes index of an element within a list.
- //
- // Within the context of Values,
- // the type of the previous, previous step value is always a message,
- // the type of the previous step value is always a list, and
- // the type of the current step value is determined by the field descriptor.
- func ListIndex(i int) Step {
- if i < 0 {
- panic(fmt.Sprintf("invalid list index: %v", i))
- }
- return Step{kind: ListIndexStep, key: protoreflect.ValueOfInt64(int64(i))}
- }
- // MapIndex describes index of an entry within a map.
- // The key type is determined by field descriptor that the map belongs to.
- //
- // Within the context of Values,
- // the type of the previous previous step value is always a message,
- // the type of the previous step value is always a map, and
- // the type of the current step value is determined by the field descriptor.
- func MapIndex(k protoreflect.MapKey) Step {
- if !k.IsValid() {
- panic("invalid map index")
- }
- return Step{kind: MapIndexStep, key: k.Value()}
- }
- // AnyExpand describes expansion of a google.protobuf.Any message into
- // a structured representation of the underlying message.
- //
- // Within the context of Values,
- // the type of the previous step value is always a google.protobuf.Any message, and
- // the type of the current step value is always a message.
- func AnyExpand(md protoreflect.MessageDescriptor) Step {
- if md == nil {
- panic("nil message descriptor")
- }
- return Step{kind: AnyExpandStep, desc: md}
- }
- // MessageDescriptor returns the message descriptor for Root or AnyExpand steps,
- // otherwise it returns nil.
- func (s Step) MessageDescriptor() protoreflect.MessageDescriptor {
- switch s.kind {
- case RootStep, AnyExpandStep:
- return s.desc.(protoreflect.MessageDescriptor)
- default:
- return nil
- }
- }
- // FieldDescriptor returns the field descriptor for FieldAccess steps,
- // otherwise it returns nil.
- func (s Step) FieldDescriptor() protoreflect.FieldDescriptor {
- switch s.kind {
- case FieldAccessStep:
- return s.desc.(protoreflect.FieldDescriptor)
- default:
- return nil
- }
- }
- // ListIndex returns the list index for ListIndex steps,
- // otherwise it returns 0.
- func (s Step) ListIndex() int {
- switch s.kind {
- case ListIndexStep:
- return int(s.key.Int())
- default:
- return 0
- }
- }
- // MapIndex returns the map key for MapIndex steps,
- // otherwise it returns an invalid map key.
- func (s Step) MapIndex() protoreflect.MapKey {
- switch s.kind {
- case MapIndexStep:
- return s.key.MapKey()
- default:
- return protoreflect.MapKey{}
- }
- }
- // Kind reports which kind of step this is.
- func (s Step) Kind() StepKind {
- return s.kind
- }
- func (s Step) String() string {
- return string(s.appendString(nil))
- }
- func (s Step) appendString(b []byte) []byte {
- switch s.kind {
- case RootStep:
- b = append(b, '(')
- b = append(b, s.desc.FullName()...)
- b = append(b, ')')
- case FieldAccessStep:
- b = append(b, '.')
- if fd := s.desc.(protoreflect.FieldDescriptor); fd.IsExtension() {
- b = append(b, '(')
- b = append(b, strings.Trim(fd.TextName(), "[]")...)
- b = append(b, ')')
- } else {
- b = append(b, fd.TextName()...)
- }
- case UnknownAccessStep:
- b = append(b, '.')
- b = append(b, '?')
- case ListIndexStep:
- b = append(b, '[')
- b = strconv.AppendInt(b, s.key.Int(), 10)
- b = append(b, ']')
- case MapIndexStep:
- b = append(b, '[')
- switch k := s.key.Interface().(type) {
- case bool:
- b = strconv.AppendBool(b, bool(k)) // e.g., "true" or "false"
- case int32:
- b = strconv.AppendInt(b, int64(k), 10) // e.g., "-32"
- case int64:
- b = strconv.AppendInt(b, int64(k), 10) // e.g., "-64"
- case uint32:
- b = strconv.AppendUint(b, uint64(k), 10) // e.g., "32"
- case uint64:
- b = strconv.AppendUint(b, uint64(k), 10) // e.g., "64"
- case string:
- b = text.AppendString(b, k) // e.g., `"hello, world"`
- }
- b = append(b, ']')
- case AnyExpandStep:
- b = append(b, '.')
- b = append(b, '(')
- b = append(b, s.desc.FullName()...)
- b = append(b, ')')
- default:
- b = append(b, "<invalid>"...)
- }
- return b
- }
|