github.com/RomiChan/protobuf@v0.1.1-0.20230204044148-2ed269a2e54d/internal/generator/init.go (about) 1 // protocolbuffers/protobuf-go cmd/protoc-gen-go/internal_gengo/init.go 2 // https://github.com/protocolbuffers/protobuf-go/blob/master/cmd/protoc-gen-go/internal_gengo/init.go 3 // 4 // Copyright © 2019 The Go Authors. All rights reserved. 5 // Portions Copyright © 2021 RomiChan 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are 9 // met: 10 // 11 // * Redistributions of source code must retain the above copyright 12 // notice, this list of conditions and the following disclaimer. 13 // * Redistributions in binary form must reproduce the above 14 // copyright notice, this list of conditions and the following disclaimer 15 // in the documentation and/or other materials provided with the 16 // distribution. 17 // * Neither the name of Google Inc. nor the names of its 18 // contributors may be used to endorse or promote products derived from 19 // this software without specific prior written permission. 20 // 21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33 package generator 34 35 import ( 36 "unicode" 37 "unicode/utf8" 38 39 "google.golang.org/protobuf/compiler/protogen" 40 "google.golang.org/protobuf/encoding/protowire" 41 "google.golang.org/protobuf/types/descriptorpb" 42 ) 43 44 type fileInfo struct { 45 *protogen.File 46 47 allEnums []*enumInfo 48 allMessages []*messageInfo 49 allExtensions []*extensionInfo 50 51 allEnumsByPtr map[*enumInfo]int // value is index into allEnums 52 allMessagesByPtr map[*messageInfo]int // value is index into allMessages 53 allMessageFieldsByPtr map[*messageInfo]*structFields 54 55 comparable bool 56 } 57 58 type structFields struct { 59 count int 60 unexported map[int]string 61 } 62 63 func (sf *structFields) append(name string) { 64 if r, _ := utf8.DecodeRuneInString(name); !unicode.IsUpper(r) { 65 if sf.unexported == nil { 66 sf.unexported = make(map[int]string) 67 } 68 sf.unexported[sf.count] = name 69 } 70 sf.count++ 71 } 72 73 func newFileInfo(file *protogen.File) *fileInfo { 74 f := &fileInfo{File: file} 75 76 // Collect all enums, messages, and extensions in "flattened ordering". 77 // See filetype.TypeBuilder. 78 var walkMessages func([]*protogen.Message, func(*protogen.Message)) 79 walkMessages = func(messages []*protogen.Message, f func(*protogen.Message)) { 80 for _, m := range messages { 81 f(m) 82 walkMessages(m.Messages, f) 83 } 84 } 85 initEnumInfos := func(enums []*protogen.Enum) { 86 for _, enum := range enums { 87 f.allEnums = append(f.allEnums, newEnumInfo(f, enum)) 88 } 89 } 90 initMessageInfos := func(messages []*protogen.Message) { 91 for _, message := range messages { 92 f.allMessages = append(f.allMessages, newMessageInfo(f, message)) 93 } 94 } 95 initExtensionInfos := func(extensions []*protogen.Extension) { 96 for _, extension := range extensions { 97 f.allExtensions = append(f.allExtensions, newExtensionInfo(f, extension)) 98 } 99 } 100 initEnumInfos(f.Enums) 101 initMessageInfos(f.Messages) 102 initExtensionInfos(f.Extensions) 103 walkMessages(f.Messages, func(m *protogen.Message) { 104 initEnumInfos(m.Enums) 105 initMessageInfos(m.Messages) 106 initExtensionInfos(m.Extensions) 107 }) 108 109 // Derive a reverse mapping of enum and message pointers to their index 110 // in allEnums and allMessages. 111 if len(f.allEnums) > 0 { 112 f.allEnumsByPtr = make(map[*enumInfo]int) 113 for i, e := range f.allEnums { 114 f.allEnumsByPtr[e] = i 115 } 116 } 117 if len(f.allMessages) > 0 { 118 f.allMessagesByPtr = make(map[*messageInfo]int) 119 f.allMessageFieldsByPtr = make(map[*messageInfo]*structFields) 120 for i, m := range f.allMessages { 121 f.allMessagesByPtr[m] = i 122 f.allMessageFieldsByPtr[m] = new(structFields) 123 } 124 } 125 126 return f 127 } 128 129 type enumInfo struct { 130 *protogen.Enum 131 } 132 133 func newEnumInfo(_ *fileInfo, enum *protogen.Enum) *enumInfo { 134 e := &enumInfo{Enum: enum} 135 return e 136 } 137 138 type messageInfo struct { 139 *protogen.Message 140 141 isTracked bool 142 } 143 144 func newMessageInfo(_ *fileInfo, message *protogen.Message) *messageInfo { 145 m := &messageInfo{Message: message} 146 m.isTracked = isTrackedMessage(m) 147 return m 148 } 149 150 // isTrackedMessage reports whether field tracking is enabled on the message. 151 func isTrackedMessage(m *messageInfo) (tracked bool) { 152 const trackFieldUseFieldNumber = 37383685 153 154 // Decode the option from unknown fields to avoid a dependency on the 155 // annotation proto from protoc-gen-go. 156 b := m.Desc.Options().(*descriptorpb.MessageOptions).ProtoReflect().GetUnknown() 157 for len(b) > 0 { 158 num, typ, n := protowire.ConsumeTag(b) 159 b = b[n:] 160 if num == trackFieldUseFieldNumber && typ == protowire.VarintType { 161 v, _ := protowire.ConsumeVarint(b) 162 tracked = protowire.DecodeBool(v) 163 } 164 m := protowire.ConsumeFieldValue(num, typ, b) 165 b = b[m:] 166 } 167 return tracked 168 } 169 170 type extensionInfo struct { 171 *protogen.Extension 172 } 173 174 func newExtensionInfo(_ *fileInfo, extension *protogen.Extension) *extensionInfo { 175 x := &extensionInfo{Extension: extension} 176 return x 177 }