blob: 1b7089b64348deb5a6dd049a5fab730b2c09eaf3 [file] [log] [blame]
Scott Baker105df152020-04-13 15:55:14 -07001// 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
5package filedesc
6
7import (
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
21type FileImports []pref.FileImport
22
23func (p *FileImports) Len() int { return len(*p) }
24func (p *FileImports) Get(i int) pref.FileImport { return (*p)[i] }
25func (p *FileImports) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
26func (p *FileImports) ProtoInternal(pragma.DoNotImplement) {}
27
28type Names struct {
29 List []pref.Name
30 once sync.Once
31 has map[pref.Name]int // protected by once
32}
33
34func (p *Names) Len() int { return len(p.List) }
35func (p *Names) Get(i int) pref.Name { return p.List[i] }
36func (p *Names) Has(s pref.Name) bool { return p.lazyInit().has[s] > 0 }
37func (p *Names) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
38func (p *Names) ProtoInternal(pragma.DoNotImplement) {}
39func (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 ..."
53func (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
67type 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
73func (p *EnumRanges) Len() int { return len(p.List) }
74func (p *EnumRanges) Get(i int) [2]pref.EnumNumber { return p.List[i] }
75func (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}
89func (p *EnumRanges) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
90func (p *EnumRanges) ProtoInternal(pragma.DoNotImplement) {}
91func (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 ..."
103func (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
118type enumRange [2]protoreflect.EnumNumber
119
120func (r enumRange) Start() protoreflect.EnumNumber { return r[0] } // inclusive
121func (r enumRange) End() protoreflect.EnumNumber { return r[1] } // inclusive
122func (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
129type 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
135func (p *FieldRanges) Len() int { return len(p.List) }
136func (p *FieldRanges) Get(i int) [2]pref.FieldNumber { return p.List[i] }
137func (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}
151func (p *FieldRanges) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
152func (p *FieldRanges) ProtoInternal(pragma.DoNotImplement) {}
153func (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 ..."
165func (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.
187func 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.
195func (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
213type fieldRange [2]protoreflect.FieldNumber
214
215func (r fieldRange) Start() protoreflect.FieldNumber { return r[0] } // inclusive
216func (r fieldRange) End() protoreflect.FieldNumber { return r[1] - 1 } // inclusive
217func (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
224type FieldNumbers struct {
225 List []pref.FieldNumber
226 once sync.Once
227 has map[pref.FieldNumber]struct{} // protected by once
228}
229
230func (p *FieldNumbers) Len() int { return len(p.List) }
231func (p *FieldNumbers) Get(i int) pref.FieldNumber { return p.List[i] }
232func (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}
244func (p *FieldNumbers) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
245func (p *FieldNumbers) ProtoInternal(pragma.DoNotImplement) {}
246
247type 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
255func (p *OneofFields) Len() int { return len(p.List) }
256func (p *OneofFields) Get(i int) pref.FieldDescriptor { return p.List[i] }
257func (p *OneofFields) ByName(s pref.Name) pref.FieldDescriptor { return p.lazyInit().byName[s] }
258func (p *OneofFields) ByJSONName(s string) pref.FieldDescriptor { return p.lazyInit().byJSON[s] }
259func (p *OneofFields) ByNumber(n pref.FieldNumber) pref.FieldDescriptor { return p.lazyInit().byNum[n] }
260func (p *OneofFields) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
261func (p *OneofFields) ProtoInternal(pragma.DoNotImplement) {}
262
263func (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
280type SourceLocations struct {
281 List []pref.SourceLocation
282}
283
284func (p *SourceLocations) Len() int { return len(p.List) }
285func (p *SourceLocations) Get(i int) pref.SourceLocation { return p.List[i] }
286func (p *SourceLocations) ProtoInternal(pragma.DoNotImplement) {}