123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- // Copyright 2019 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 filedesc
- import (
- "fmt"
- "math"
- "sort"
- "sync"
- "google.golang.org/protobuf/internal/genid"
- "google.golang.org/protobuf/encoding/protowire"
- "google.golang.org/protobuf/internal/descfmt"
- "google.golang.org/protobuf/internal/errors"
- "google.golang.org/protobuf/internal/pragma"
- "google.golang.org/protobuf/reflect/protoreflect"
- pref "google.golang.org/protobuf/reflect/protoreflect"
- )
- type FileImports []pref.FileImport
- func (p *FileImports) Len() int { return len(*p) }
- func (p *FileImports) Get(i int) pref.FileImport { return (*p)[i] }
- func (p *FileImports) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
- func (p *FileImports) ProtoInternal(pragma.DoNotImplement) {}
- type Names struct {
- List []pref.Name
- once sync.Once
- has map[pref.Name]int // protected by once
- }
- func (p *Names) Len() int { return len(p.List) }
- func (p *Names) Get(i int) pref.Name { return p.List[i] }
- func (p *Names) Has(s pref.Name) bool { return p.lazyInit().has[s] > 0 }
- func (p *Names) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
- func (p *Names) ProtoInternal(pragma.DoNotImplement) {}
- func (p *Names) lazyInit() *Names {
- p.once.Do(func() {
- if len(p.List) > 0 {
- p.has = make(map[pref.Name]int, len(p.List))
- for _, s := range p.List {
- p.has[s] = p.has[s] + 1
- }
- }
- })
- return p
- }
- // CheckValid reports any errors with the set of names with an error message
- // that completes the sentence: "ranges is invalid because it has ..."
- func (p *Names) CheckValid() error {
- for s, n := range p.lazyInit().has {
- switch {
- case n > 1:
- return errors.New("duplicate name: %q", s)
- case false && !s.IsValid():
- // NOTE: The C++ implementation does not validate the identifier.
- // See https://github.com/protocolbuffers/protobuf/issues/6335.
- return errors.New("invalid name: %q", s)
- }
- }
- return nil
- }
- type EnumRanges struct {
- List [][2]pref.EnumNumber // start inclusive; end inclusive
- once sync.Once
- sorted [][2]pref.EnumNumber // protected by once
- }
- func (p *EnumRanges) Len() int { return len(p.List) }
- func (p *EnumRanges) Get(i int) [2]pref.EnumNumber { return p.List[i] }
- func (p *EnumRanges) Has(n pref.EnumNumber) bool {
- for ls := p.lazyInit().sorted; len(ls) > 0; {
- i := len(ls) / 2
- switch r := enumRange(ls[i]); {
- case n < r.Start():
- ls = ls[:i] // search lower
- case n > r.End():
- ls = ls[i+1:] // search upper
- default:
- return true
- }
- }
- return false
- }
- func (p *EnumRanges) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
- func (p *EnumRanges) ProtoInternal(pragma.DoNotImplement) {}
- func (p *EnumRanges) lazyInit() *EnumRanges {
- p.once.Do(func() {
- p.sorted = append(p.sorted, p.List...)
- sort.Slice(p.sorted, func(i, j int) bool {
- return p.sorted[i][0] < p.sorted[j][0]
- })
- })
- return p
- }
- // CheckValid reports any errors with the set of names with an error message
- // that completes the sentence: "ranges is invalid because it has ..."
- func (p *EnumRanges) CheckValid() error {
- var rp enumRange
- for i, r := range p.lazyInit().sorted {
- r := enumRange(r)
- switch {
- case !(r.Start() <= r.End()):
- return errors.New("invalid range: %v", r)
- case !(rp.End() < r.Start()) && i > 0:
- return errors.New("overlapping ranges: %v with %v", rp, r)
- }
- rp = r
- }
- return nil
- }
- type enumRange [2]protoreflect.EnumNumber
- func (r enumRange) Start() protoreflect.EnumNumber { return r[0] } // inclusive
- func (r enumRange) End() protoreflect.EnumNumber { return r[1] } // inclusive
- func (r enumRange) String() string {
- if r.Start() == r.End() {
- return fmt.Sprintf("%d", r.Start())
- }
- return fmt.Sprintf("%d to %d", r.Start(), r.End())
- }
- type FieldRanges struct {
- List [][2]pref.FieldNumber // start inclusive; end exclusive
- once sync.Once
- sorted [][2]pref.FieldNumber // protected by once
- }
- func (p *FieldRanges) Len() int { return len(p.List) }
- func (p *FieldRanges) Get(i int) [2]pref.FieldNumber { return p.List[i] }
- func (p *FieldRanges) Has(n pref.FieldNumber) bool {
- for ls := p.lazyInit().sorted; len(ls) > 0; {
- i := len(ls) / 2
- switch r := fieldRange(ls[i]); {
- case n < r.Start():
- ls = ls[:i] // search lower
- case n > r.End():
- ls = ls[i+1:] // search upper
- default:
- return true
- }
- }
- return false
- }
- func (p *FieldRanges) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
- func (p *FieldRanges) ProtoInternal(pragma.DoNotImplement) {}
- func (p *FieldRanges) lazyInit() *FieldRanges {
- p.once.Do(func() {
- p.sorted = append(p.sorted, p.List...)
- sort.Slice(p.sorted, func(i, j int) bool {
- return p.sorted[i][0] < p.sorted[j][0]
- })
- })
- return p
- }
- // CheckValid reports any errors with the set of ranges with an error message
- // that completes the sentence: "ranges is invalid because it has ..."
- func (p *FieldRanges) CheckValid(isMessageSet bool) error {
- var rp fieldRange
- for i, r := range p.lazyInit().sorted {
- r := fieldRange(r)
- switch {
- case !isValidFieldNumber(r.Start(), isMessageSet):
- return errors.New("invalid field number: %d", r.Start())
- case !isValidFieldNumber(r.End(), isMessageSet):
- return errors.New("invalid field number: %d", r.End())
- case !(r.Start() <= r.End()):
- return errors.New("invalid range: %v", r)
- case !(rp.End() < r.Start()) && i > 0:
- return errors.New("overlapping ranges: %v with %v", rp, r)
- }
- rp = r
- }
- return nil
- }
- // isValidFieldNumber reports whether the field number is valid.
- // Unlike the FieldNumber.IsValid method, it allows ranges that cover the
- // reserved number range.
- func isValidFieldNumber(n protoreflect.FieldNumber, isMessageSet bool) bool {
- return protowire.MinValidNumber <= n && (n <= protowire.MaxValidNumber || isMessageSet)
- }
- // CheckOverlap reports an error if p and q overlap.
- func (p *FieldRanges) CheckOverlap(q *FieldRanges) error {
- rps := p.lazyInit().sorted
- rqs := q.lazyInit().sorted
- for pi, qi := 0, 0; pi < len(rps) && qi < len(rqs); {
- rp := fieldRange(rps[pi])
- rq := fieldRange(rqs[qi])
- if !(rp.End() < rq.Start() || rq.End() < rp.Start()) {
- return errors.New("overlapping ranges: %v with %v", rp, rq)
- }
- if rp.Start() < rq.Start() {
- pi++
- } else {
- qi++
- }
- }
- return nil
- }
- type fieldRange [2]protoreflect.FieldNumber
- func (r fieldRange) Start() protoreflect.FieldNumber { return r[0] } // inclusive
- func (r fieldRange) End() protoreflect.FieldNumber { return r[1] - 1 } // inclusive
- func (r fieldRange) String() string {
- if r.Start() == r.End() {
- return fmt.Sprintf("%d", r.Start())
- }
- return fmt.Sprintf("%d to %d", r.Start(), r.End())
- }
- type FieldNumbers struct {
- List []pref.FieldNumber
- once sync.Once
- has map[pref.FieldNumber]struct{} // protected by once
- }
- func (p *FieldNumbers) Len() int { return len(p.List) }
- func (p *FieldNumbers) Get(i int) pref.FieldNumber { return p.List[i] }
- func (p *FieldNumbers) Has(n pref.FieldNumber) bool {
- p.once.Do(func() {
- if len(p.List) > 0 {
- p.has = make(map[pref.FieldNumber]struct{}, len(p.List))
- for _, n := range p.List {
- p.has[n] = struct{}{}
- }
- }
- })
- _, ok := p.has[n]
- return ok
- }
- func (p *FieldNumbers) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
- func (p *FieldNumbers) ProtoInternal(pragma.DoNotImplement) {}
- type OneofFields struct {
- List []pref.FieldDescriptor
- once sync.Once
- byName map[pref.Name]pref.FieldDescriptor // protected by once
- byJSON map[string]pref.FieldDescriptor // protected by once
- byText map[string]pref.FieldDescriptor // protected by once
- byNum map[pref.FieldNumber]pref.FieldDescriptor // protected by once
- }
- func (p *OneofFields) Len() int { return len(p.List) }
- func (p *OneofFields) Get(i int) pref.FieldDescriptor { return p.List[i] }
- func (p *OneofFields) ByName(s pref.Name) pref.FieldDescriptor { return p.lazyInit().byName[s] }
- func (p *OneofFields) ByJSONName(s string) pref.FieldDescriptor { return p.lazyInit().byJSON[s] }
- func (p *OneofFields) ByTextName(s string) pref.FieldDescriptor { return p.lazyInit().byText[s] }
- func (p *OneofFields) ByNumber(n pref.FieldNumber) pref.FieldDescriptor { return p.lazyInit().byNum[n] }
- func (p *OneofFields) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
- func (p *OneofFields) ProtoInternal(pragma.DoNotImplement) {}
- func (p *OneofFields) lazyInit() *OneofFields {
- p.once.Do(func() {
- if len(p.List) > 0 {
- p.byName = make(map[pref.Name]pref.FieldDescriptor, len(p.List))
- p.byJSON = make(map[string]pref.FieldDescriptor, len(p.List))
- p.byText = make(map[string]pref.FieldDescriptor, len(p.List))
- p.byNum = make(map[pref.FieldNumber]pref.FieldDescriptor, len(p.List))
- for _, f := range p.List {
- // Field names and numbers are guaranteed to be unique.
- p.byName[f.Name()] = f
- p.byJSON[f.JSONName()] = f
- p.byText[f.TextName()] = f
- p.byNum[f.Number()] = f
- }
- }
- })
- return p
- }
- type SourceLocations struct {
- // List is a list of SourceLocations.
- // The SourceLocation.Next field does not need to be populated
- // as it will be lazily populated upon first need.
- List []pref.SourceLocation
- // File is the parent file descriptor that these locations are relative to.
- // If non-nil, ByDescriptor verifies that the provided descriptor
- // is a child of this file descriptor.
- File pref.FileDescriptor
- once sync.Once
- byPath map[pathKey]int
- }
- func (p *SourceLocations) Len() int { return len(p.List) }
- func (p *SourceLocations) Get(i int) pref.SourceLocation { return p.lazyInit().List[i] }
- func (p *SourceLocations) byKey(k pathKey) pref.SourceLocation {
- if i, ok := p.lazyInit().byPath[k]; ok {
- return p.List[i]
- }
- return pref.SourceLocation{}
- }
- func (p *SourceLocations) ByPath(path pref.SourcePath) pref.SourceLocation {
- return p.byKey(newPathKey(path))
- }
- func (p *SourceLocations) ByDescriptor(desc pref.Descriptor) pref.SourceLocation {
- if p.File != nil && desc != nil && p.File != desc.ParentFile() {
- return pref.SourceLocation{} // mismatching parent files
- }
- var pathArr [16]int32
- path := pathArr[:0]
- for {
- switch desc.(type) {
- case pref.FileDescriptor:
- // Reverse the path since it was constructed in reverse.
- for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
- path[i], path[j] = path[j], path[i]
- }
- return p.byKey(newPathKey(path))
- case pref.MessageDescriptor:
- path = append(path, int32(desc.Index()))
- desc = desc.Parent()
- switch desc.(type) {
- case pref.FileDescriptor:
- path = append(path, int32(genid.FileDescriptorProto_MessageType_field_number))
- case pref.MessageDescriptor:
- path = append(path, int32(genid.DescriptorProto_NestedType_field_number))
- default:
- return pref.SourceLocation{}
- }
- case pref.FieldDescriptor:
- isExtension := desc.(pref.FieldDescriptor).IsExtension()
- path = append(path, int32(desc.Index()))
- desc = desc.Parent()
- if isExtension {
- switch desc.(type) {
- case pref.FileDescriptor:
- path = append(path, int32(genid.FileDescriptorProto_Extension_field_number))
- case pref.MessageDescriptor:
- path = append(path, int32(genid.DescriptorProto_Extension_field_number))
- default:
- return pref.SourceLocation{}
- }
- } else {
- switch desc.(type) {
- case pref.MessageDescriptor:
- path = append(path, int32(genid.DescriptorProto_Field_field_number))
- default:
- return pref.SourceLocation{}
- }
- }
- case pref.OneofDescriptor:
- path = append(path, int32(desc.Index()))
- desc = desc.Parent()
- switch desc.(type) {
- case pref.MessageDescriptor:
- path = append(path, int32(genid.DescriptorProto_OneofDecl_field_number))
- default:
- return pref.SourceLocation{}
- }
- case pref.EnumDescriptor:
- path = append(path, int32(desc.Index()))
- desc = desc.Parent()
- switch desc.(type) {
- case pref.FileDescriptor:
- path = append(path, int32(genid.FileDescriptorProto_EnumType_field_number))
- case pref.MessageDescriptor:
- path = append(path, int32(genid.DescriptorProto_EnumType_field_number))
- default:
- return pref.SourceLocation{}
- }
- case pref.EnumValueDescriptor:
- path = append(path, int32(desc.Index()))
- desc = desc.Parent()
- switch desc.(type) {
- case pref.EnumDescriptor:
- path = append(path, int32(genid.EnumDescriptorProto_Value_field_number))
- default:
- return pref.SourceLocation{}
- }
- case pref.ServiceDescriptor:
- path = append(path, int32(desc.Index()))
- desc = desc.Parent()
- switch desc.(type) {
- case pref.FileDescriptor:
- path = append(path, int32(genid.FileDescriptorProto_Service_field_number))
- default:
- return pref.SourceLocation{}
- }
- case pref.MethodDescriptor:
- path = append(path, int32(desc.Index()))
- desc = desc.Parent()
- switch desc.(type) {
- case pref.ServiceDescriptor:
- path = append(path, int32(genid.ServiceDescriptorProto_Method_field_number))
- default:
- return pref.SourceLocation{}
- }
- default:
- return pref.SourceLocation{}
- }
- }
- }
- func (p *SourceLocations) lazyInit() *SourceLocations {
- p.once.Do(func() {
- if len(p.List) > 0 {
- // Collect all the indexes for a given path.
- pathIdxs := make(map[pathKey][]int, len(p.List))
- for i, l := range p.List {
- k := newPathKey(l.Path)
- pathIdxs[k] = append(pathIdxs[k], i)
- }
- // Update the next index for all locations.
- p.byPath = make(map[pathKey]int, len(p.List))
- for k, idxs := range pathIdxs {
- for i := 0; i < len(idxs)-1; i++ {
- p.List[idxs[i]].Next = idxs[i+1]
- }
- p.List[idxs[len(idxs)-1]].Next = 0
- p.byPath[k] = idxs[0] // record the first location for this path
- }
- }
- })
- return p
- }
- func (p *SourceLocations) ProtoInternal(pragma.DoNotImplement) {}
- // pathKey is a comparable representation of protoreflect.SourcePath.
- type pathKey struct {
- arr [16]uint8 // first n-1 path segments; last element is the length
- str string // used if the path does not fit in arr
- }
- func newPathKey(p pref.SourcePath) (k pathKey) {
- if len(p) < len(k.arr) {
- for i, ps := range p {
- if ps < 0 || math.MaxUint8 <= ps {
- return pathKey{str: p.String()}
- }
- k.arr[i] = uint8(ps)
- }
- k.arr[len(k.arr)-1] = uint8(len(p))
- return k
- }
- return pathKey{str: p.String()}
- }
|