xref: /aosp_15_r20/external/golang-protobuf/internal/filedesc/desc_list.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
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
5package filedesc
6
7import (
8	"fmt"
9	"math"
10	"sort"
11	"sync"
12
13	"google.golang.org/protobuf/internal/genid"
14
15	"google.golang.org/protobuf/encoding/protowire"
16	"google.golang.org/protobuf/internal/descfmt"
17	"google.golang.org/protobuf/internal/errors"
18	"google.golang.org/protobuf/internal/pragma"
19	"google.golang.org/protobuf/reflect/protoreflect"
20)
21
22type FileImports []protoreflect.FileImport
23
24func (p *FileImports) Len() int                            { return len(*p) }
25func (p *FileImports) Get(i int) protoreflect.FileImport   { return (*p)[i] }
26func (p *FileImports) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
27func (p *FileImports) ProtoInternal(pragma.DoNotImplement) {}
28
29type Names struct {
30	List []protoreflect.Name
31	once sync.Once
32	has  map[protoreflect.Name]int // protected by once
33}
34
35func (p *Names) Len() int                            { return len(p.List) }
36func (p *Names) Get(i int) protoreflect.Name         { return p.List[i] }
37func (p *Names) Has(s protoreflect.Name) bool        { return p.lazyInit().has[s] > 0 }
38func (p *Names) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
39func (p *Names) ProtoInternal(pragma.DoNotImplement) {}
40func (p *Names) lazyInit() *Names {
41	p.once.Do(func() {
42		if len(p.List) > 0 {
43			p.has = make(map[protoreflect.Name]int, len(p.List))
44			for _, s := range p.List {
45				p.has[s] = p.has[s] + 1
46			}
47		}
48	})
49	return p
50}
51
52// CheckValid reports any errors with the set of names with an error message
53// that completes the sentence: "ranges is invalid because it has ..."
54func (p *Names) CheckValid() error {
55	for s, n := range p.lazyInit().has {
56		switch {
57		case n > 1:
58			return errors.New("duplicate name: %q", s)
59		case false && !s.IsValid():
60			// NOTE: The C++ implementation does not validate the identifier.
61			// See https://github.com/protocolbuffers/protobuf/issues/6335.
62			return errors.New("invalid name: %q", s)
63		}
64	}
65	return nil
66}
67
68type EnumRanges struct {
69	List   [][2]protoreflect.EnumNumber // start inclusive; end inclusive
70	once   sync.Once
71	sorted [][2]protoreflect.EnumNumber // protected by once
72}
73
74func (p *EnumRanges) Len() int                             { return len(p.List) }
75func (p *EnumRanges) Get(i int) [2]protoreflect.EnumNumber { return p.List[i] }
76func (p *EnumRanges) Has(n protoreflect.EnumNumber) bool {
77	for ls := p.lazyInit().sorted; len(ls) > 0; {
78		i := len(ls) / 2
79		switch r := enumRange(ls[i]); {
80		case n < r.Start():
81			ls = ls[:i] // search lower
82		case n > r.End():
83			ls = ls[i+1:] // search upper
84		default:
85			return true
86		}
87	}
88	return false
89}
90func (p *EnumRanges) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
91func (p *EnumRanges) ProtoInternal(pragma.DoNotImplement) {}
92func (p *EnumRanges) lazyInit() *EnumRanges {
93	p.once.Do(func() {
94		p.sorted = append(p.sorted, p.List...)
95		sort.Slice(p.sorted, func(i, j int) bool {
96			return p.sorted[i][0] < p.sorted[j][0]
97		})
98	})
99	return p
100}
101
102// CheckValid reports any errors with the set of names with an error message
103// that completes the sentence: "ranges is invalid because it has ..."
104func (p *EnumRanges) CheckValid() error {
105	var rp enumRange
106	for i, r := range p.lazyInit().sorted {
107		r := enumRange(r)
108		switch {
109		case !(r.Start() <= r.End()):
110			return errors.New("invalid range: %v", r)
111		case !(rp.End() < r.Start()) && i > 0:
112			return errors.New("overlapping ranges: %v with %v", rp, r)
113		}
114		rp = r
115	}
116	return nil
117}
118
119type enumRange [2]protoreflect.EnumNumber
120
121func (r enumRange) Start() protoreflect.EnumNumber { return r[0] } // inclusive
122func (r enumRange) End() protoreflect.EnumNumber   { return r[1] } // inclusive
123func (r enumRange) String() string {
124	if r.Start() == r.End() {
125		return fmt.Sprintf("%d", r.Start())
126	}
127	return fmt.Sprintf("%d to %d", r.Start(), r.End())
128}
129
130type FieldRanges struct {
131	List   [][2]protoreflect.FieldNumber // start inclusive; end exclusive
132	once   sync.Once
133	sorted [][2]protoreflect.FieldNumber // protected by once
134}
135
136func (p *FieldRanges) Len() int                              { return len(p.List) }
137func (p *FieldRanges) Get(i int) [2]protoreflect.FieldNumber { return p.List[i] }
138func (p *FieldRanges) Has(n protoreflect.FieldNumber) bool {
139	for ls := p.lazyInit().sorted; len(ls) > 0; {
140		i := len(ls) / 2
141		switch r := fieldRange(ls[i]); {
142		case n < r.Start():
143			ls = ls[:i] // search lower
144		case n > r.End():
145			ls = ls[i+1:] // search upper
146		default:
147			return true
148		}
149	}
150	return false
151}
152func (p *FieldRanges) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
153func (p *FieldRanges) ProtoInternal(pragma.DoNotImplement) {}
154func (p *FieldRanges) lazyInit() *FieldRanges {
155	p.once.Do(func() {
156		p.sorted = append(p.sorted, p.List...)
157		sort.Slice(p.sorted, func(i, j int) bool {
158			return p.sorted[i][0] < p.sorted[j][0]
159		})
160	})
161	return p
162}
163
164// CheckValid reports any errors with the set of ranges with an error message
165// that completes the sentence: "ranges is invalid because it has ..."
166func (p *FieldRanges) CheckValid(isMessageSet bool) error {
167	var rp fieldRange
168	for i, r := range p.lazyInit().sorted {
169		r := fieldRange(r)
170		switch {
171		case !isValidFieldNumber(r.Start(), isMessageSet):
172			return errors.New("invalid field number: %d", r.Start())
173		case !isValidFieldNumber(r.End(), isMessageSet):
174			return errors.New("invalid field number: %d", r.End())
175		case !(r.Start() <= r.End()):
176			return errors.New("invalid range: %v", r)
177		case !(rp.End() < r.Start()) && i > 0:
178			return errors.New("overlapping ranges: %v with %v", rp, r)
179		}
180		rp = r
181	}
182	return nil
183}
184
185// isValidFieldNumber reports whether the field number is valid.
186// Unlike the FieldNumber.IsValid method, it allows ranges that cover the
187// reserved number range.
188func isValidFieldNumber(n protoreflect.FieldNumber, isMessageSet bool) bool {
189	return protowire.MinValidNumber <= n && (n <= protowire.MaxValidNumber || isMessageSet)
190}
191
192// CheckOverlap reports an error if p and q overlap.
193func (p *FieldRanges) CheckOverlap(q *FieldRanges) error {
194	rps := p.lazyInit().sorted
195	rqs := q.lazyInit().sorted
196	for pi, qi := 0, 0; pi < len(rps) && qi < len(rqs); {
197		rp := fieldRange(rps[pi])
198		rq := fieldRange(rqs[qi])
199		if !(rp.End() < rq.Start() || rq.End() < rp.Start()) {
200			return errors.New("overlapping ranges: %v with %v", rp, rq)
201		}
202		if rp.Start() < rq.Start() {
203			pi++
204		} else {
205			qi++
206		}
207	}
208	return nil
209}
210
211type fieldRange [2]protoreflect.FieldNumber
212
213func (r fieldRange) Start() protoreflect.FieldNumber { return r[0] }     // inclusive
214func (r fieldRange) End() protoreflect.FieldNumber   { return r[1] - 1 } // inclusive
215func (r fieldRange) String() string {
216	if r.Start() == r.End() {
217		return fmt.Sprintf("%d", r.Start())
218	}
219	return fmt.Sprintf("%d to %d", r.Start(), r.End())
220}
221
222type FieldNumbers struct {
223	List []protoreflect.FieldNumber
224	once sync.Once
225	has  map[protoreflect.FieldNumber]struct{} // protected by once
226}
227
228func (p *FieldNumbers) Len() int                           { return len(p.List) }
229func (p *FieldNumbers) Get(i int) protoreflect.FieldNumber { return p.List[i] }
230func (p *FieldNumbers) Has(n protoreflect.FieldNumber) bool {
231	p.once.Do(func() {
232		if len(p.List) > 0 {
233			p.has = make(map[protoreflect.FieldNumber]struct{}, len(p.List))
234			for _, n := range p.List {
235				p.has[n] = struct{}{}
236			}
237		}
238	})
239	_, ok := p.has[n]
240	return ok
241}
242func (p *FieldNumbers) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
243func (p *FieldNumbers) ProtoInternal(pragma.DoNotImplement) {}
244
245type OneofFields struct {
246	List   []protoreflect.FieldDescriptor
247	once   sync.Once
248	byName map[protoreflect.Name]protoreflect.FieldDescriptor        // protected by once
249	byJSON map[string]protoreflect.FieldDescriptor                   // protected by once
250	byText map[string]protoreflect.FieldDescriptor                   // protected by once
251	byNum  map[protoreflect.FieldNumber]protoreflect.FieldDescriptor // protected by once
252}
253
254func (p *OneofFields) Len() int                               { return len(p.List) }
255func (p *OneofFields) Get(i int) protoreflect.FieldDescriptor { return p.List[i] }
256func (p *OneofFields) ByName(s protoreflect.Name) protoreflect.FieldDescriptor {
257	return p.lazyInit().byName[s]
258}
259func (p *OneofFields) ByJSONName(s string) protoreflect.FieldDescriptor {
260	return p.lazyInit().byJSON[s]
261}
262func (p *OneofFields) ByTextName(s string) protoreflect.FieldDescriptor {
263	return p.lazyInit().byText[s]
264}
265func (p *OneofFields) ByNumber(n protoreflect.FieldNumber) protoreflect.FieldDescriptor {
266	return p.lazyInit().byNum[n]
267}
268func (p *OneofFields) Format(s fmt.State, r rune)          { descfmt.FormatList(s, r, p) }
269func (p *OneofFields) ProtoInternal(pragma.DoNotImplement) {}
270
271func (p *OneofFields) lazyInit() *OneofFields {
272	p.once.Do(func() {
273		if len(p.List) > 0 {
274			p.byName = make(map[protoreflect.Name]protoreflect.FieldDescriptor, len(p.List))
275			p.byJSON = make(map[string]protoreflect.FieldDescriptor, len(p.List))
276			p.byText = make(map[string]protoreflect.FieldDescriptor, len(p.List))
277			p.byNum = make(map[protoreflect.FieldNumber]protoreflect.FieldDescriptor, len(p.List))
278			for _, f := range p.List {
279				// Field names and numbers are guaranteed to be unique.
280				p.byName[f.Name()] = f
281				p.byJSON[f.JSONName()] = f
282				p.byText[f.TextName()] = f
283				p.byNum[f.Number()] = f
284			}
285		}
286	})
287	return p
288}
289
290type SourceLocations struct {
291	// List is a list of SourceLocations.
292	// The SourceLocation.Next field does not need to be populated
293	// as it will be lazily populated upon first need.
294	List []protoreflect.SourceLocation
295
296	// File is the parent file descriptor that these locations are relative to.
297	// If non-nil, ByDescriptor verifies that the provided descriptor
298	// is a child of this file descriptor.
299	File protoreflect.FileDescriptor
300
301	once   sync.Once
302	byPath map[pathKey]int
303}
304
305func (p *SourceLocations) Len() int                              { return len(p.List) }
306func (p *SourceLocations) Get(i int) protoreflect.SourceLocation { return p.lazyInit().List[i] }
307func (p *SourceLocations) byKey(k pathKey) protoreflect.SourceLocation {
308	if i, ok := p.lazyInit().byPath[k]; ok {
309		return p.List[i]
310	}
311	return protoreflect.SourceLocation{}
312}
313func (p *SourceLocations) ByPath(path protoreflect.SourcePath) protoreflect.SourceLocation {
314	return p.byKey(newPathKey(path))
315}
316func (p *SourceLocations) ByDescriptor(desc protoreflect.Descriptor) protoreflect.SourceLocation {
317	if p.File != nil && desc != nil && p.File != desc.ParentFile() {
318		return protoreflect.SourceLocation{} // mismatching parent files
319	}
320	var pathArr [16]int32
321	path := pathArr[:0]
322	for {
323		switch desc.(type) {
324		case protoreflect.FileDescriptor:
325			// Reverse the path since it was constructed in reverse.
326			for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
327				path[i], path[j] = path[j], path[i]
328			}
329			return p.byKey(newPathKey(path))
330		case protoreflect.MessageDescriptor:
331			path = append(path, int32(desc.Index()))
332			desc = desc.Parent()
333			switch desc.(type) {
334			case protoreflect.FileDescriptor:
335				path = append(path, int32(genid.FileDescriptorProto_MessageType_field_number))
336			case protoreflect.MessageDescriptor:
337				path = append(path, int32(genid.DescriptorProto_NestedType_field_number))
338			default:
339				return protoreflect.SourceLocation{}
340			}
341		case protoreflect.FieldDescriptor:
342			isExtension := desc.(protoreflect.FieldDescriptor).IsExtension()
343			path = append(path, int32(desc.Index()))
344			desc = desc.Parent()
345			if isExtension {
346				switch desc.(type) {
347				case protoreflect.FileDescriptor:
348					path = append(path, int32(genid.FileDescriptorProto_Extension_field_number))
349				case protoreflect.MessageDescriptor:
350					path = append(path, int32(genid.DescriptorProto_Extension_field_number))
351				default:
352					return protoreflect.SourceLocation{}
353				}
354			} else {
355				switch desc.(type) {
356				case protoreflect.MessageDescriptor:
357					path = append(path, int32(genid.DescriptorProto_Field_field_number))
358				default:
359					return protoreflect.SourceLocation{}
360				}
361			}
362		case protoreflect.OneofDescriptor:
363			path = append(path, int32(desc.Index()))
364			desc = desc.Parent()
365			switch desc.(type) {
366			case protoreflect.MessageDescriptor:
367				path = append(path, int32(genid.DescriptorProto_OneofDecl_field_number))
368			default:
369				return protoreflect.SourceLocation{}
370			}
371		case protoreflect.EnumDescriptor:
372			path = append(path, int32(desc.Index()))
373			desc = desc.Parent()
374			switch desc.(type) {
375			case protoreflect.FileDescriptor:
376				path = append(path, int32(genid.FileDescriptorProto_EnumType_field_number))
377			case protoreflect.MessageDescriptor:
378				path = append(path, int32(genid.DescriptorProto_EnumType_field_number))
379			default:
380				return protoreflect.SourceLocation{}
381			}
382		case protoreflect.EnumValueDescriptor:
383			path = append(path, int32(desc.Index()))
384			desc = desc.Parent()
385			switch desc.(type) {
386			case protoreflect.EnumDescriptor:
387				path = append(path, int32(genid.EnumDescriptorProto_Value_field_number))
388			default:
389				return protoreflect.SourceLocation{}
390			}
391		case protoreflect.ServiceDescriptor:
392			path = append(path, int32(desc.Index()))
393			desc = desc.Parent()
394			switch desc.(type) {
395			case protoreflect.FileDescriptor:
396				path = append(path, int32(genid.FileDescriptorProto_Service_field_number))
397			default:
398				return protoreflect.SourceLocation{}
399			}
400		case protoreflect.MethodDescriptor:
401			path = append(path, int32(desc.Index()))
402			desc = desc.Parent()
403			switch desc.(type) {
404			case protoreflect.ServiceDescriptor:
405				path = append(path, int32(genid.ServiceDescriptorProto_Method_field_number))
406			default:
407				return protoreflect.SourceLocation{}
408			}
409		default:
410			return protoreflect.SourceLocation{}
411		}
412	}
413}
414func (p *SourceLocations) lazyInit() *SourceLocations {
415	p.once.Do(func() {
416		if len(p.List) > 0 {
417			// Collect all the indexes for a given path.
418			pathIdxs := make(map[pathKey][]int, len(p.List))
419			for i, l := range p.List {
420				k := newPathKey(l.Path)
421				pathIdxs[k] = append(pathIdxs[k], i)
422			}
423
424			// Update the next index for all locations.
425			p.byPath = make(map[pathKey]int, len(p.List))
426			for k, idxs := range pathIdxs {
427				for i := 0; i < len(idxs)-1; i++ {
428					p.List[idxs[i]].Next = idxs[i+1]
429				}
430				p.List[idxs[len(idxs)-1]].Next = 0
431				p.byPath[k] = idxs[0] // record the first location for this path
432			}
433		}
434	})
435	return p
436}
437func (p *SourceLocations) ProtoInternal(pragma.DoNotImplement) {}
438
439// pathKey is a comparable representation of protoreflect.SourcePath.
440type pathKey struct {
441	arr [16]uint8 // first n-1 path segments; last element is the length
442	str string    // used if the path does not fit in arr
443}
444
445func newPathKey(p protoreflect.SourcePath) (k pathKey) {
446	if len(p) < len(k.arr) {
447		for i, ps := range p {
448			if ps < 0 || math.MaxUint8 <= ps {
449				return pathKey{str: p.String()}
450			}
451			k.arr[i] = uint8(ps)
452		}
453		k.arr[len(k.arr)-1] = uint8(len(p))
454		return k
455	}
456	return pathKey{str: p.String()}
457}
458