...
1
2
3
4
5 package protodesc
6
7 import (
8 _ "embed"
9 "fmt"
10 "os"
11 "sync"
12
13 "google.golang.org/protobuf/internal/filedesc"
14 "google.golang.org/protobuf/proto"
15 "google.golang.org/protobuf/types/descriptorpb"
16 )
17
18 const (
19 SupportedEditionsMinimum = descriptorpb.Edition_EDITION_PROTO2
20 SupportedEditionsMaximum = descriptorpb.Edition_EDITION_2023
21 )
22
23
24 var binaryEditionDefaults []byte
25 var defaults = &descriptorpb.FeatureSetDefaults{}
26 var defaultsCacheMu sync.Mutex
27 var defaultsCache = make(map[filedesc.Edition]*descriptorpb.FeatureSet)
28
29 func init() {
30 err := proto.Unmarshal(binaryEditionDefaults, defaults)
31 if err != nil {
32 fmt.Fprintf(os.Stderr, "unmarshal editions defaults: %v\n", err)
33 os.Exit(1)
34 }
35 }
36
37 func fromEditionProto(epb descriptorpb.Edition) filedesc.Edition {
38 return filedesc.Edition(epb)
39 }
40
41 func toEditionProto(ed filedesc.Edition) descriptorpb.Edition {
42 switch ed {
43 case filedesc.EditionUnknown:
44 return descriptorpb.Edition_EDITION_UNKNOWN
45 case filedesc.EditionProto2:
46 return descriptorpb.Edition_EDITION_PROTO2
47 case filedesc.EditionProto3:
48 return descriptorpb.Edition_EDITION_PROTO3
49 case filedesc.Edition2023:
50 return descriptorpb.Edition_EDITION_2023
51 default:
52 panic(fmt.Sprintf("unknown value for edition: %v", ed))
53 }
54 }
55
56 func getFeatureSetFor(ed filedesc.Edition) *descriptorpb.FeatureSet {
57 defaultsCacheMu.Lock()
58 defer defaultsCacheMu.Unlock()
59 if def, ok := defaultsCache[ed]; ok {
60 return def
61 }
62 edpb := toEditionProto(ed)
63 if defaults.GetMinimumEdition() > edpb || defaults.GetMaximumEdition() < edpb {
64
65
66
67 fmt.Fprintf(os.Stderr, "internal error: unsupported edition %v (did you forget to update the embedded defaults (i.e. the bootstrap descriptor proto)?)\n", edpb)
68 os.Exit(1)
69 }
70 fs := defaults.GetDefaults()[0].GetFeatures()
71
72
73
74
75 for _, def := range defaults.GetDefaults() {
76 if def.GetEdition() <= edpb {
77 fs = def.GetFeatures()
78 } else {
79 break
80 }
81 }
82 defaultsCache[ed] = fs
83 return fs
84 }
85
86 func resolveFeatureHasFieldPresence(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
87 fs := fieldDesc.GetOptions().GetFeatures()
88 if fs == nil || fs.FieldPresence == nil {
89 return fileDesc.L1.EditionFeatures.IsFieldPresence
90 }
91 return fs.GetFieldPresence() == descriptorpb.FeatureSet_LEGACY_REQUIRED ||
92 fs.GetFieldPresence() == descriptorpb.FeatureSet_EXPLICIT
93 }
94
95 func resolveFeatureRepeatedFieldEncodingPacked(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
96 fs := fieldDesc.GetOptions().GetFeatures()
97 if fs == nil || fs.RepeatedFieldEncoding == nil {
98 return fileDesc.L1.EditionFeatures.IsPacked
99 }
100 return fs.GetRepeatedFieldEncoding() == descriptorpb.FeatureSet_PACKED
101 }
102
103 func resolveFeatureEnforceUTF8(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
104 fs := fieldDesc.GetOptions().GetFeatures()
105 if fs == nil || fs.Utf8Validation == nil {
106 return fileDesc.L1.EditionFeatures.IsUTF8Validated
107 }
108 return fs.GetUtf8Validation() == descriptorpb.FeatureSet_VERIFY
109 }
110
111 func resolveFeatureDelimitedEncoding(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
112 fs := fieldDesc.GetOptions().GetFeatures()
113 if fs == nil || fs.MessageEncoding == nil {
114 return fileDesc.L1.EditionFeatures.IsDelimitedEncoded
115 }
116 return fs.GetMessageEncoding() == descriptorpb.FeatureSet_DELIMITED
117 }
118
119
120
121
122
123 func initFileDescFromFeatureSet(fd *filedesc.File, fs *descriptorpb.FeatureSet) {
124 dfs := getFeatureSetFor(fd.L1.Edition)
125 if fs == nil {
126 fs = &descriptorpb.FeatureSet{}
127 }
128
129 var fieldPresence descriptorpb.FeatureSet_FieldPresence
130 if fp := fs.FieldPresence; fp != nil {
131 fieldPresence = *fp
132 } else {
133 fieldPresence = *dfs.FieldPresence
134 }
135 fd.L1.EditionFeatures.IsFieldPresence = fieldPresence == descriptorpb.FeatureSet_LEGACY_REQUIRED ||
136 fieldPresence == descriptorpb.FeatureSet_EXPLICIT
137
138 var enumType descriptorpb.FeatureSet_EnumType
139 if et := fs.EnumType; et != nil {
140 enumType = *et
141 } else {
142 enumType = *dfs.EnumType
143 }
144 fd.L1.EditionFeatures.IsOpenEnum = enumType == descriptorpb.FeatureSet_OPEN
145
146 var respeatedFieldEncoding descriptorpb.FeatureSet_RepeatedFieldEncoding
147 if rfe := fs.RepeatedFieldEncoding; rfe != nil {
148 respeatedFieldEncoding = *rfe
149 } else {
150 respeatedFieldEncoding = *dfs.RepeatedFieldEncoding
151 }
152 fd.L1.EditionFeatures.IsPacked = respeatedFieldEncoding == descriptorpb.FeatureSet_PACKED
153
154 var isUTF8Validated descriptorpb.FeatureSet_Utf8Validation
155 if utf8val := fs.Utf8Validation; utf8val != nil {
156 isUTF8Validated = *utf8val
157 } else {
158 isUTF8Validated = *dfs.Utf8Validation
159 }
160 fd.L1.EditionFeatures.IsUTF8Validated = isUTF8Validated == descriptorpb.FeatureSet_VERIFY
161
162 var messageEncoding descriptorpb.FeatureSet_MessageEncoding
163 if me := fs.MessageEncoding; me != nil {
164 messageEncoding = *me
165 } else {
166 messageEncoding = *dfs.MessageEncoding
167 }
168 fd.L1.EditionFeatures.IsDelimitedEncoded = messageEncoding == descriptorpb.FeatureSet_DELIMITED
169
170 var jsonFormat descriptorpb.FeatureSet_JsonFormat
171 if jf := fs.JsonFormat; jf != nil {
172 jsonFormat = *jf
173 } else {
174 jsonFormat = *dfs.JsonFormat
175 }
176 fd.L1.EditionFeatures.IsJSONCompliant = jsonFormat == descriptorpb.FeatureSet_ALLOW
177 }
178
View as plain text