...

Source file src/google.golang.org/protobuf/reflect/protopath/step.go

Documentation: google.golang.org/protobuf/reflect/protopath

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

View as plain text