package protodesc
import (
"fmt"
"strings"
"google.golang.org/protobuf/internal/encoding/defval"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)
func ToFileDescriptorProto (file protoreflect .FileDescriptor ) *descriptorpb .FileDescriptorProto {
p := &descriptorpb .FileDescriptorProto {
Name : proto .String (file .Path ()),
Options : proto .Clone (file .Options ()).(*descriptorpb .FileOptions ),
}
if file .Package () != "" {
p .Package = proto .String (string (file .Package ()))
}
for i , imports := 0 , file .Imports (); i < imports .Len (); i ++ {
imp := imports .Get (i )
p .Dependency = append (p .Dependency , imp .Path ())
if imp .IsPublic {
p .PublicDependency = append (p .PublicDependency , int32 (i ))
}
}
for i , locs := 0 , file .SourceLocations (); i < locs .Len (); i ++ {
loc := locs .Get (i )
l := &descriptorpb .SourceCodeInfo_Location {}
l .Path = append (l .Path , loc .Path ...)
if loc .StartLine == loc .EndLine {
l .Span = []int32 {int32 (loc .StartLine ), int32 (loc .StartColumn ), int32 (loc .EndColumn )}
} else {
l .Span = []int32 {int32 (loc .StartLine ), int32 (loc .StartColumn ), int32 (loc .EndLine ), int32 (loc .EndColumn )}
}
l .LeadingDetachedComments = append ([]string (nil ), loc .LeadingDetachedComments ...)
if loc .LeadingComments != "" {
l .LeadingComments = proto .String (loc .LeadingComments )
}
if loc .TrailingComments != "" {
l .TrailingComments = proto .String (loc .TrailingComments )
}
if p .SourceCodeInfo == nil {
p .SourceCodeInfo = &descriptorpb .SourceCodeInfo {}
}
p .SourceCodeInfo .Location = append (p .SourceCodeInfo .Location , l )
}
for i , messages := 0 , file .Messages (); i < messages .Len (); i ++ {
p .MessageType = append (p .MessageType , ToDescriptorProto (messages .Get (i )))
}
for i , enums := 0 , file .Enums (); i < enums .Len (); i ++ {
p .EnumType = append (p .EnumType , ToEnumDescriptorProto (enums .Get (i )))
}
for i , services := 0 , file .Services (); i < services .Len (); i ++ {
p .Service = append (p .Service , ToServiceDescriptorProto (services .Get (i )))
}
for i , exts := 0 , file .Extensions (); i < exts .Len (); i ++ {
p .Extension = append (p .Extension , ToFieldDescriptorProto (exts .Get (i )))
}
if syntax := file .Syntax (); syntax != protoreflect .Proto2 && syntax .IsValid () {
p .Syntax = proto .String (file .Syntax ().String ())
}
if file .Syntax () == protoreflect .Editions {
desc := file
if fileImportDesc , ok := file .(protoreflect .FileImport ); ok {
desc = fileImportDesc .FileDescriptor
}
if editionsInterface , ok := desc .(interface { Edition () int32 }); ok {
p .Edition = descriptorpb .Edition (editionsInterface .Edition ()).Enum ()
}
}
return p
}
func ToDescriptorProto (message protoreflect .MessageDescriptor ) *descriptorpb .DescriptorProto {
p := &descriptorpb .DescriptorProto {
Name : proto .String (string (message .Name ())),
Options : proto .Clone (message .Options ()).(*descriptorpb .MessageOptions ),
}
for i , fields := 0 , message .Fields (); i < fields .Len (); i ++ {
p .Field = append (p .Field , ToFieldDescriptorProto (fields .Get (i )))
}
for i , exts := 0 , message .Extensions (); i < exts .Len (); i ++ {
p .Extension = append (p .Extension , ToFieldDescriptorProto (exts .Get (i )))
}
for i , messages := 0 , message .Messages (); i < messages .Len (); i ++ {
p .NestedType = append (p .NestedType , ToDescriptorProto (messages .Get (i )))
}
for i , enums := 0 , message .Enums (); i < enums .Len (); i ++ {
p .EnumType = append (p .EnumType , ToEnumDescriptorProto (enums .Get (i )))
}
for i , xranges := 0 , message .ExtensionRanges (); i < xranges .Len (); i ++ {
xrange := xranges .Get (i )
p .ExtensionRange = append (p .ExtensionRange , &descriptorpb .DescriptorProto_ExtensionRange {
Start : proto .Int32 (int32 (xrange [0 ])),
End : proto .Int32 (int32 (xrange [1 ])),
Options : proto .Clone (message .ExtensionRangeOptions (i )).(*descriptorpb .ExtensionRangeOptions ),
})
}
for i , oneofs := 0 , message .Oneofs (); i < oneofs .Len (); i ++ {
p .OneofDecl = append (p .OneofDecl , ToOneofDescriptorProto (oneofs .Get (i )))
}
for i , ranges := 0 , message .ReservedRanges (); i < ranges .Len (); i ++ {
rrange := ranges .Get (i )
p .ReservedRange = append (p .ReservedRange , &descriptorpb .DescriptorProto_ReservedRange {
Start : proto .Int32 (int32 (rrange [0 ])),
End : proto .Int32 (int32 (rrange [1 ])),
})
}
for i , names := 0 , message .ReservedNames (); i < names .Len (); i ++ {
p .ReservedName = append (p .ReservedName , string (names .Get (i )))
}
return p
}
func ToFieldDescriptorProto (field protoreflect .FieldDescriptor ) *descriptorpb .FieldDescriptorProto {
p := &descriptorpb .FieldDescriptorProto {
Name : proto .String (string (field .Name ())),
Number : proto .Int32 (int32 (field .Number ())),
Label : descriptorpb .FieldDescriptorProto_Label (field .Cardinality ()).Enum (),
Options : proto .Clone (field .Options ()).(*descriptorpb .FieldOptions ),
}
if field .IsExtension () {
p .Extendee = fullNameOf (field .ContainingMessage ())
}
if field .Kind ().IsValid () {
p .Type = descriptorpb .FieldDescriptorProto_Type (field .Kind ()).Enum ()
}
if field .Enum () != nil {
p .TypeName = fullNameOf (field .Enum ())
}
if field .Message () != nil {
p .TypeName = fullNameOf (field .Message ())
}
if field .HasJSONName () {
if field .IsExtension () {
p .JsonName = proto .String (strs .JSONCamelCase (string (field .Name ())))
} else {
p .JsonName = proto .String (field .JSONName ())
}
}
if field .Syntax () == protoreflect .Proto3 && field .HasOptionalKeyword () {
p .Proto3Optional = proto .Bool (true )
}
if field .Syntax () == protoreflect .Editions {
if p .GetType () == descriptorpb .FieldDescriptorProto_TYPE_GROUP {
p .Type = descriptorpb .FieldDescriptorProto_TYPE_MESSAGE .Enum ()
}
if p .GetLabel () == descriptorpb .FieldDescriptorProto_LABEL_REQUIRED {
p .Label = descriptorpb .FieldDescriptorProto_LABEL_OPTIONAL .Enum ()
}
}
if field .HasDefault () {
def , err := defval .Marshal (field .Default (), field .DefaultEnumValue (), field .Kind (), defval .Descriptor )
if err != nil && field .DefaultEnumValue () != nil {
def = string (field .DefaultEnumValue ().Name ())
} else if err != nil {
panic (fmt .Sprintf ("%v: %v" , field .FullName (), err ))
}
p .DefaultValue = proto .String (def )
}
if oneof := field .ContainingOneof (); oneof != nil {
p .OneofIndex = proto .Int32 (int32 (oneof .Index ()))
}
return p
}
func ToOneofDescriptorProto (oneof protoreflect .OneofDescriptor ) *descriptorpb .OneofDescriptorProto {
return &descriptorpb .OneofDescriptorProto {
Name : proto .String (string (oneof .Name ())),
Options : proto .Clone (oneof .Options ()).(*descriptorpb .OneofOptions ),
}
}
func ToEnumDescriptorProto (enum protoreflect .EnumDescriptor ) *descriptorpb .EnumDescriptorProto {
p := &descriptorpb .EnumDescriptorProto {
Name : proto .String (string (enum .Name ())),
Options : proto .Clone (enum .Options ()).(*descriptorpb .EnumOptions ),
}
for i , values := 0 , enum .Values (); i < values .Len (); i ++ {
p .Value = append (p .Value , ToEnumValueDescriptorProto (values .Get (i )))
}
for i , ranges := 0 , enum .ReservedRanges (); i < ranges .Len (); i ++ {
rrange := ranges .Get (i )
p .ReservedRange = append (p .ReservedRange , &descriptorpb .EnumDescriptorProto_EnumReservedRange {
Start : proto .Int32 (int32 (rrange [0 ])),
End : proto .Int32 (int32 (rrange [1 ])),
})
}
for i , names := 0 , enum .ReservedNames (); i < names .Len (); i ++ {
p .ReservedName = append (p .ReservedName , string (names .Get (i )))
}
return p
}
func ToEnumValueDescriptorProto (value protoreflect .EnumValueDescriptor ) *descriptorpb .EnumValueDescriptorProto {
return &descriptorpb .EnumValueDescriptorProto {
Name : proto .String (string (value .Name ())),
Number : proto .Int32 (int32 (value .Number ())),
Options : proto .Clone (value .Options ()).(*descriptorpb .EnumValueOptions ),
}
}
func ToServiceDescriptorProto (service protoreflect .ServiceDescriptor ) *descriptorpb .ServiceDescriptorProto {
p := &descriptorpb .ServiceDescriptorProto {
Name : proto .String (string (service .Name ())),
Options : proto .Clone (service .Options ()).(*descriptorpb .ServiceOptions ),
}
for i , methods := 0 , service .Methods (); i < methods .Len (); i ++ {
p .Method = append (p .Method , ToMethodDescriptorProto (methods .Get (i )))
}
return p
}
func ToMethodDescriptorProto (method protoreflect .MethodDescriptor ) *descriptorpb .MethodDescriptorProto {
p := &descriptorpb .MethodDescriptorProto {
Name : proto .String (string (method .Name ())),
InputType : fullNameOf (method .Input ()),
OutputType : fullNameOf (method .Output ()),
Options : proto .Clone (method .Options ()).(*descriptorpb .MethodOptions ),
}
if method .IsStreamingClient () {
p .ClientStreaming = proto .Bool (true )
}
if method .IsStreamingServer () {
p .ServerStreaming = proto .Bool (true )
}
return p
}
func fullNameOf(d protoreflect .Descriptor ) *string {
if d == nil {
return nil
}
if strings .HasPrefix (string (d .FullName ()), unknownPrefix ) {
return proto .String (string (d .FullName ()[len (unknownPrefix ):]))
}
return proto .String ("." + string (d .FullName ()))
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .