129 lines
2.8 KiB
Go
129 lines
2.8 KiB
Go
package protowalk
|
|
|
|
import (
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
)
|
|
|
|
type WalkFunc func(desc protoreflect.Descriptor) bool
|
|
|
|
func WalkFiles(files []protoreflect.FileDescriptor, f WalkFunc) {
|
|
var w walker
|
|
w.walkFiles(files, f)
|
|
}
|
|
|
|
type walker struct {
|
|
seen map[string]struct{}
|
|
}
|
|
|
|
func (w *walker) enter(name string) bool {
|
|
if _, ok := w.seen[name]; ok {
|
|
return false
|
|
}
|
|
if w.seen == nil {
|
|
w.seen = make(map[string]struct{})
|
|
}
|
|
w.seen[name] = struct{}{}
|
|
return true
|
|
}
|
|
|
|
func (w *walker) walkFiles(files []protoreflect.FileDescriptor, f WalkFunc) {
|
|
for _, file := range files {
|
|
w.walkFile(file, f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkFile(file protoreflect.FileDescriptor, f WalkFunc) {
|
|
if w.enter(file.Path()) {
|
|
if !f(file) {
|
|
return
|
|
}
|
|
w.walkEnums(file.Enums(), f)
|
|
w.walkMessages(file.Messages(), f)
|
|
w.walkServices(file.Services(), f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkEnums(enums protoreflect.EnumDescriptors, f WalkFunc) {
|
|
for i := 0; i < enums.Len(); i++ {
|
|
w.walkEnum(enums.Get(i), f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkEnum(enum protoreflect.EnumDescriptor, f WalkFunc) {
|
|
if w.enter(string(enum.FullName())) {
|
|
f(enum)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkMessages(messages protoreflect.MessageDescriptors, f WalkFunc) {
|
|
for i := 0; i < messages.Len(); i++ {
|
|
w.walkMessage(messages.Get(i), f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkMessage(message protoreflect.MessageDescriptor, f WalkFunc) {
|
|
if w.enter(string(message.FullName())) {
|
|
if !f(message) {
|
|
return
|
|
}
|
|
w.walkFields(message.Fields(), f)
|
|
w.walkMessages(message.Messages(), f)
|
|
w.walkEnums(message.Enums(), f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkFields(fields protoreflect.FieldDescriptors, f WalkFunc) {
|
|
for i := 0; i < fields.Len(); i++ {
|
|
w.walkField(fields.Get(i), f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkField(field protoreflect.FieldDescriptor, f WalkFunc) {
|
|
if w.enter(string(field.FullName())) {
|
|
if !f(field) {
|
|
return
|
|
}
|
|
if field.IsMap() {
|
|
w.walkField(field.MapKey(), f)
|
|
w.walkField(field.MapValue(), f)
|
|
}
|
|
if field.Message() != nil {
|
|
w.walkMessage(field.Message(), f)
|
|
}
|
|
if field.Enum() != nil {
|
|
w.walkEnum(field.Enum(), f)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkServices(services protoreflect.ServiceDescriptors, f WalkFunc) {
|
|
for i := 0; i < services.Len(); i++ {
|
|
w.walkService(services.Get(i), f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkService(service protoreflect.ServiceDescriptor, f WalkFunc) {
|
|
if w.enter(string(service.FullName())) {
|
|
if !f(service) {
|
|
return
|
|
}
|
|
w.walkMethods(service.Methods(), f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkMethods(methods protoreflect.MethodDescriptors, f WalkFunc) {
|
|
for i := 0; i < methods.Len(); i++ {
|
|
w.walkMethod(methods.Get(i), f)
|
|
}
|
|
}
|
|
|
|
func (w *walker) walkMethod(method protoreflect.MethodDescriptor, f WalkFunc) {
|
|
if w.enter(string(method.FullName())) {
|
|
if !f(method) {
|
|
return
|
|
}
|
|
w.walkMessage(method.Input(), f)
|
|
w.walkMessage(method.Output(), f)
|
|
}
|
|
}
|