mpagenko | af80163 | 2020-07-03 10:00:42 +0000 | [diff] [blame] | 1 | // Copyright 2019 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 filedesc |
| 6 | |
| 7 | import ( |
| 8 | "fmt" |
| 9 | "math" |
| 10 | "sort" |
| 11 | "sync" |
| 12 | |
| 13 | "google.golang.org/protobuf/encoding/protowire" |
| 14 | "google.golang.org/protobuf/internal/descfmt" |
| 15 | "google.golang.org/protobuf/internal/errors" |
| 16 | "google.golang.org/protobuf/internal/pragma" |
| 17 | "google.golang.org/protobuf/reflect/protoreflect" |
| 18 | pref "google.golang.org/protobuf/reflect/protoreflect" |
| 19 | ) |
| 20 | |
| 21 | type FileImports []pref.FileImport |
| 22 | |
| 23 | func (p *FileImports) Len() int { return len(*p) } |
| 24 | func (p *FileImports) Get(i int) pref.FileImport { return (*p)[i] } |
| 25 | func (p *FileImports) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) } |
| 26 | func (p *FileImports) ProtoInternal(pragma.DoNotImplement) {} |
| 27 | |
| 28 | type Names struct { |
| 29 | List []pref.Name |
| 30 | once sync.Once |
| 31 | has map[pref.Name]int // protected by once |
| 32 | } |
| 33 | |
| 34 | func (p *Names) Len() int { return len(p.List) } |
| 35 | func (p *Names) Get(i int) pref.Name { return p.List[i] } |
| 36 | func (p *Names) Has(s pref.Name) bool { return p.lazyInit().has[s] > 0 } |
| 37 | func (p *Names) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) } |
| 38 | func (p *Names) ProtoInternal(pragma.DoNotImplement) {} |
| 39 | func (p *Names) lazyInit() *Names { |
| 40 | p.once.Do(func() { |
| 41 | if len(p.List) > 0 { |
| 42 | p.has = make(map[pref.Name]int, len(p.List)) |
| 43 | for _, s := range p.List { |
| 44 | p.has[s] = p.has[s] + 1 |
| 45 | } |
| 46 | } |
| 47 | }) |
| 48 | return p |
| 49 | } |
| 50 | |
| 51 | // CheckValid reports any errors with the set of names with an error message |
| 52 | // that completes the sentence: "ranges is invalid because it has ..." |
| 53 | func (p *Names) CheckValid() error { |
| 54 | for s, n := range p.lazyInit().has { |
| 55 | switch { |
| 56 | case n > 1: |
| 57 | return errors.New("duplicate name: %q", s) |
| 58 | case false && !s.IsValid(): |
| 59 | // NOTE: The C++ implementation does not validate the identifier. |
| 60 | // See https://github.com/protocolbuffers/protobuf/issues/6335. |
| 61 | return errors.New("invalid name: %q", s) |
| 62 | } |
| 63 | } |
| 64 | return nil |
| 65 | } |
| 66 | |
| 67 | type EnumRanges struct { |
| 68 | List [][2]pref.EnumNumber // start inclusive; end inclusive |
| 69 | once sync.Once |
| 70 | sorted [][2]pref.EnumNumber // protected by once |
| 71 | } |
| 72 | |
| 73 | func (p *EnumRanges) Len() int { return len(p.List) } |
| 74 | func (p *EnumRanges) Get(i int) [2]pref.EnumNumber { return p.List[i] } |
| 75 | func (p *EnumRanges) Has(n pref.EnumNumber) bool { |
| 76 | for ls := p.lazyInit().sorted; len(ls) > 0; { |
| 77 | i := len(ls) / 2 |
| 78 | switch r := enumRange(ls[i]); { |
| 79 | case n < r.Start(): |
| 80 | ls = ls[:i] // search lower |
| 81 | case n > r.End(): |
| 82 | ls = ls[i+1:] // search upper |
| 83 | default: |
| 84 | return true |
| 85 | } |
| 86 | } |
| 87 | return false |
| 88 | } |
| 89 | func (p *EnumRanges) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) } |
| 90 | func (p *EnumRanges) ProtoInternal(pragma.DoNotImplement) {} |
| 91 | func (p *EnumRanges) lazyInit() *EnumRanges { |
| 92 | p.once.Do(func() { |
| 93 | p.sorted = append(p.sorted, p.List...) |
| 94 | sort.Slice(p.sorted, func(i, j int) bool { |
| 95 | return p.sorted[i][0] < p.sorted[j][0] |
| 96 | }) |
| 97 | }) |
| 98 | return p |
| 99 | } |
| 100 | |
| 101 | // CheckValid reports any errors with the set of names with an error message |
| 102 | // that completes the sentence: "ranges is invalid because it has ..." |
| 103 | func (p *EnumRanges) CheckValid() error { |
| 104 | var rp enumRange |
| 105 | for i, r := range p.lazyInit().sorted { |
| 106 | r := enumRange(r) |
| 107 | switch { |
| 108 | case !(r.Start() <= r.End()): |
| 109 | return errors.New("invalid range: %v", r) |
| 110 | case !(rp.End() < r.Start()) && i > 0: |
| 111 | return errors.New("overlapping ranges: %v with %v", rp, r) |
| 112 | } |
| 113 | rp = r |
| 114 | } |
| 115 | return nil |
| 116 | } |
| 117 | |
| 118 | type enumRange [2]protoreflect.EnumNumber |
| 119 | |
| 120 | func (r enumRange) Start() protoreflect.EnumNumber { return r[0] } // inclusive |
| 121 | func (r enumRange) End() protoreflect.EnumNumber { return r[1] } // inclusive |
| 122 | func (r enumRange) String() string { |
| 123 | if r.Start() == r.End() { |
| 124 | return fmt.Sprintf("%d", r.Start()) |
| 125 | } |
| 126 | return fmt.Sprintf("%d to %d", r.Start(), r.End()) |
| 127 | } |
| 128 | |
| 129 | type FieldRanges struct { |
| 130 | List [][2]pref.FieldNumber // start inclusive; end exclusive |
| 131 | once sync.Once |
| 132 | sorted [][2]pref.FieldNumber // protected by once |
| 133 | } |
| 134 | |
| 135 | func (p *FieldRanges) Len() int { return len(p.List) } |
| 136 | func (p *FieldRanges) Get(i int) [2]pref.FieldNumber { return p.List[i] } |
| 137 | func (p *FieldRanges) Has(n pref.FieldNumber) bool { |
| 138 | for ls := p.lazyInit().sorted; len(ls) > 0; { |
| 139 | i := len(ls) / 2 |
| 140 | switch r := fieldRange(ls[i]); { |
| 141 | case n < r.Start(): |
| 142 | ls = ls[:i] // search lower |
| 143 | case n > r.End(): |
| 144 | ls = ls[i+1:] // search upper |
| 145 | default: |
| 146 | return true |
| 147 | } |
| 148 | } |
| 149 | return false |
| 150 | } |
| 151 | func (p *FieldRanges) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) } |
| 152 | func (p *FieldRanges) ProtoInternal(pragma.DoNotImplement) {} |
| 153 | func (p *FieldRanges) lazyInit() *FieldRanges { |
| 154 | p.once.Do(func() { |
| 155 | p.sorted = append(p.sorted, p.List...) |
| 156 | sort.Slice(p.sorted, func(i, j int) bool { |
| 157 | return p.sorted[i][0] < p.sorted[j][0] |
| 158 | }) |
| 159 | }) |
| 160 | return p |
| 161 | } |
| 162 | |
| 163 | // CheckValid reports any errors with the set of ranges with an error message |
| 164 | // that completes the sentence: "ranges is invalid because it has ..." |
| 165 | func (p *FieldRanges) CheckValid(isMessageSet bool) error { |
| 166 | var rp fieldRange |
| 167 | for i, r := range p.lazyInit().sorted { |
| 168 | r := fieldRange(r) |
| 169 | switch { |
| 170 | case !isValidFieldNumber(r.Start(), isMessageSet): |
| 171 | return errors.New("invalid field number: %d", r.Start()) |
| 172 | case !isValidFieldNumber(r.End(), isMessageSet): |
| 173 | return errors.New("invalid field number: %d", r.End()) |
| 174 | case !(r.Start() <= r.End()): |
| 175 | return errors.New("invalid range: %v", r) |
| 176 | case !(rp.End() < r.Start()) && i > 0: |
| 177 | return errors.New("overlapping ranges: %v with %v", rp, r) |
| 178 | } |
| 179 | rp = r |
| 180 | } |
| 181 | return nil |
| 182 | } |
| 183 | |
| 184 | // isValidFieldNumber reports whether the field number is valid. |
| 185 | // Unlike the FieldNumber.IsValid method, it allows ranges that cover the |
| 186 | // reserved number range. |
| 187 | func isValidFieldNumber(n protoreflect.FieldNumber, isMessageSet bool) bool { |
| 188 | if isMessageSet { |
| 189 | return protowire.MinValidNumber <= n && n <= math.MaxInt32 |
| 190 | } |
| 191 | return protowire.MinValidNumber <= n && n <= protowire.MaxValidNumber |
| 192 | } |
| 193 | |
| 194 | // CheckOverlap reports an error if p and q overlap. |
| 195 | func (p *FieldRanges) CheckOverlap(q *FieldRanges) error { |
| 196 | rps := p.lazyInit().sorted |
| 197 | rqs := q.lazyInit().sorted |
| 198 | for pi, qi := 0, 0; pi < len(rps) && qi < len(rqs); { |
| 199 | rp := fieldRange(rps[pi]) |
| 200 | rq := fieldRange(rqs[qi]) |
| 201 | if !(rp.End() < rq.Start() || rq.End() < rp.Start()) { |
| 202 | return errors.New("overlapping ranges: %v with %v", rp, rq) |
| 203 | } |
| 204 | if rp.Start() < rq.Start() { |
| 205 | pi++ |
| 206 | } else { |
| 207 | qi++ |
| 208 | } |
| 209 | } |
| 210 | return nil |
| 211 | } |
| 212 | |
| 213 | type fieldRange [2]protoreflect.FieldNumber |
| 214 | |
| 215 | func (r fieldRange) Start() protoreflect.FieldNumber { return r[0] } // inclusive |
| 216 | func (r fieldRange) End() protoreflect.FieldNumber { return r[1] - 1 } // inclusive |
| 217 | func (r fieldRange) String() string { |
| 218 | if r.Start() == r.End() { |
| 219 | return fmt.Sprintf("%d", r.Start()) |
| 220 | } |
| 221 | return fmt.Sprintf("%d to %d", r.Start(), r.End()) |
| 222 | } |
| 223 | |
| 224 | type FieldNumbers struct { |
| 225 | List []pref.FieldNumber |
| 226 | once sync.Once |
| 227 | has map[pref.FieldNumber]struct{} // protected by once |
| 228 | } |
| 229 | |
| 230 | func (p *FieldNumbers) Len() int { return len(p.List) } |
| 231 | func (p *FieldNumbers) Get(i int) pref.FieldNumber { return p.List[i] } |
| 232 | func (p *FieldNumbers) Has(n pref.FieldNumber) bool { |
| 233 | p.once.Do(func() { |
| 234 | if len(p.List) > 0 { |
| 235 | p.has = make(map[pref.FieldNumber]struct{}, len(p.List)) |
| 236 | for _, n := range p.List { |
| 237 | p.has[n] = struct{}{} |
| 238 | } |
| 239 | } |
| 240 | }) |
| 241 | _, ok := p.has[n] |
| 242 | return ok |
| 243 | } |
| 244 | func (p *FieldNumbers) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) } |
| 245 | func (p *FieldNumbers) ProtoInternal(pragma.DoNotImplement) {} |
| 246 | |
| 247 | type OneofFields struct { |
| 248 | List []pref.FieldDescriptor |
| 249 | once sync.Once |
| 250 | byName map[pref.Name]pref.FieldDescriptor // protected by once |
| 251 | byJSON map[string]pref.FieldDescriptor // protected by once |
| 252 | byNum map[pref.FieldNumber]pref.FieldDescriptor // protected by once |
| 253 | } |
| 254 | |
| 255 | func (p *OneofFields) Len() int { return len(p.List) } |
| 256 | func (p *OneofFields) Get(i int) pref.FieldDescriptor { return p.List[i] } |
| 257 | func (p *OneofFields) ByName(s pref.Name) pref.FieldDescriptor { return p.lazyInit().byName[s] } |
| 258 | func (p *OneofFields) ByJSONName(s string) pref.FieldDescriptor { return p.lazyInit().byJSON[s] } |
| 259 | func (p *OneofFields) ByNumber(n pref.FieldNumber) pref.FieldDescriptor { return p.lazyInit().byNum[n] } |
| 260 | func (p *OneofFields) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) } |
| 261 | func (p *OneofFields) ProtoInternal(pragma.DoNotImplement) {} |
| 262 | |
| 263 | func (p *OneofFields) lazyInit() *OneofFields { |
| 264 | p.once.Do(func() { |
| 265 | if len(p.List) > 0 { |
| 266 | p.byName = make(map[pref.Name]pref.FieldDescriptor, len(p.List)) |
| 267 | p.byJSON = make(map[string]pref.FieldDescriptor, len(p.List)) |
| 268 | p.byNum = make(map[pref.FieldNumber]pref.FieldDescriptor, len(p.List)) |
| 269 | for _, f := range p.List { |
| 270 | // Field names and numbers are guaranteed to be unique. |
| 271 | p.byName[f.Name()] = f |
| 272 | p.byJSON[f.JSONName()] = f |
| 273 | p.byNum[f.Number()] = f |
| 274 | } |
| 275 | } |
| 276 | }) |
| 277 | return p |
| 278 | } |
| 279 | |
| 280 | type SourceLocations struct { |
| 281 | List []pref.SourceLocation |
| 282 | } |
| 283 | |
| 284 | func (p *SourceLocations) Len() int { return len(p.List) } |
| 285 | func (p *SourceLocations) Get(i int) pref.SourceLocation { return p.List[i] } |
| 286 | func (p *SourceLocations) ProtoInternal(pragma.DoNotImplement) {} |