blob: 66ba906806fccb3fda28deecc640e60c816ee457 [file] [log] [blame]
Abhay Kumara61c5222025-11-10 07:32:50 +00001// Copyright 2024 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
10 "google.golang.org/protobuf/encoding/protowire"
11 "google.golang.org/protobuf/internal/editiondefaults"
12 "google.golang.org/protobuf/internal/genid"
13 "google.golang.org/protobuf/reflect/protoreflect"
14)
15
16var (
17 defaultsCache = make(map[Edition]EditionFeatures)
18 defaultsKeys = []Edition{}
19)
20
21func init() {
22 unmarshalEditionDefaults(editiondefaults.Defaults)
23 SurrogateProto2.L1.EditionFeatures = getFeaturesFor(EditionProto2)
24 SurrogateProto3.L1.EditionFeatures = getFeaturesFor(EditionProto3)
25 SurrogateEdition2023.L1.EditionFeatures = getFeaturesFor(Edition2023)
26}
27
28func unmarshalGoFeature(b []byte, parent EditionFeatures) EditionFeatures {
29 for len(b) > 0 {
30 num, _, n := protowire.ConsumeTag(b)
31 b = b[n:]
32 switch num {
33 case genid.GoFeatures_LegacyUnmarshalJsonEnum_field_number:
34 v, m := protowire.ConsumeVarint(b)
35 b = b[m:]
36 parent.GenerateLegacyUnmarshalJSON = protowire.DecodeBool(v)
37 case genid.GoFeatures_ApiLevel_field_number:
38 v, m := protowire.ConsumeVarint(b)
39 b = b[m:]
40 parent.APILevel = int(v)
41 case genid.GoFeatures_StripEnumPrefix_field_number:
42 v, m := protowire.ConsumeVarint(b)
43 b = b[m:]
44 parent.StripEnumPrefix = int(v)
45 default:
46 panic(fmt.Sprintf("unknown field number %d while unmarshalling GoFeatures", num))
47 }
48 }
49 return parent
50}
51
52func unmarshalFeatureSet(b []byte, parent EditionFeatures) EditionFeatures {
53 for len(b) > 0 {
54 num, typ, n := protowire.ConsumeTag(b)
55 b = b[n:]
56 switch typ {
57 case protowire.VarintType:
58 v, m := protowire.ConsumeVarint(b)
59 b = b[m:]
60 switch num {
61 case genid.FeatureSet_FieldPresence_field_number:
62 parent.IsFieldPresence = v == genid.FeatureSet_EXPLICIT_enum_value || v == genid.FeatureSet_LEGACY_REQUIRED_enum_value
63 parent.IsLegacyRequired = v == genid.FeatureSet_LEGACY_REQUIRED_enum_value
64 case genid.FeatureSet_EnumType_field_number:
65 parent.IsOpenEnum = v == genid.FeatureSet_OPEN_enum_value
66 case genid.FeatureSet_RepeatedFieldEncoding_field_number:
67 parent.IsPacked = v == genid.FeatureSet_PACKED_enum_value
68 case genid.FeatureSet_Utf8Validation_field_number:
69 parent.IsUTF8Validated = v == genid.FeatureSet_VERIFY_enum_value
70 case genid.FeatureSet_MessageEncoding_field_number:
71 parent.IsDelimitedEncoded = v == genid.FeatureSet_DELIMITED_enum_value
72 case genid.FeatureSet_JsonFormat_field_number:
73 parent.IsJSONCompliant = v == genid.FeatureSet_ALLOW_enum_value
74 case genid.FeatureSet_EnforceNamingStyle_field_number:
75 // EnforceNamingStyle is enforced in protoc, languages other than C++
76 // are not supposed to do anything with this feature.
77 case genid.FeatureSet_DefaultSymbolVisibility_field_number:
78 // DefaultSymbolVisibility is enforced in protoc, runtimes should not
79 // inspect this value.
80 default:
81 panic(fmt.Sprintf("unknown field number %d while unmarshalling FeatureSet", num))
82 }
83 case protowire.BytesType:
84 v, m := protowire.ConsumeBytes(b)
85 b = b[m:]
86 switch num {
87 case genid.FeatureSet_Go_ext_number:
88 parent = unmarshalGoFeature(v, parent)
89 }
90 }
91 }
92
93 return parent
94}
95
96func featuresFromParentDesc(parentDesc protoreflect.Descriptor) EditionFeatures {
97 var parentFS EditionFeatures
98 switch p := parentDesc.(type) {
99 case *File:
100 parentFS = p.L1.EditionFeatures
101 case *Message:
102 parentFS = p.L1.EditionFeatures
103 default:
104 panic(fmt.Sprintf("unknown parent type %T", parentDesc))
105 }
106 return parentFS
107}
108
109func unmarshalEditionDefault(b []byte) {
110 var ed Edition
111 var fs EditionFeatures
112 for len(b) > 0 {
113 num, typ, n := protowire.ConsumeTag(b)
114 b = b[n:]
115 switch typ {
116 case protowire.VarintType:
117 v, m := protowire.ConsumeVarint(b)
118 b = b[m:]
119 switch num {
120 case genid.FeatureSetDefaults_FeatureSetEditionDefault_Edition_field_number:
121 ed = Edition(v)
122 }
123 case protowire.BytesType:
124 v, m := protowire.ConsumeBytes(b)
125 b = b[m:]
126 switch num {
127 case genid.FeatureSetDefaults_FeatureSetEditionDefault_FixedFeatures_field_number:
128 fs = unmarshalFeatureSet(v, fs)
129 case genid.FeatureSetDefaults_FeatureSetEditionDefault_OverridableFeatures_field_number:
130 fs = unmarshalFeatureSet(v, fs)
131 }
132 }
133 }
134 defaultsCache[ed] = fs
135 defaultsKeys = append(defaultsKeys, ed)
136}
137
138func unmarshalEditionDefaults(b []byte) {
139 for len(b) > 0 {
140 num, _, n := protowire.ConsumeTag(b)
141 b = b[n:]
142 switch num {
143 case genid.FeatureSetDefaults_Defaults_field_number:
144 def, m := protowire.ConsumeBytes(b)
145 b = b[m:]
146 unmarshalEditionDefault(def)
147 case genid.FeatureSetDefaults_MinimumEdition_field_number,
148 genid.FeatureSetDefaults_MaximumEdition_field_number:
149 // We don't care about the minimum and maximum editions. If the
150 // edition we are looking for later on is not in the cache we know
151 // it is outside of the range between minimum and maximum edition.
152 _, m := protowire.ConsumeVarint(b)
153 b = b[m:]
154 default:
155 panic(fmt.Sprintf("unknown field number %d while unmarshalling EditionDefault", num))
156 }
157 }
158}
159
160func getFeaturesFor(ed Edition) EditionFeatures {
161 match := EditionUnknown
162 for _, key := range defaultsKeys {
163 if key > ed {
164 break
165 }
166 match = key
167 }
168 if match == EditionUnknown {
169 panic(fmt.Sprintf("unsupported edition: %v", ed))
170 }
171 return defaultsCache[match]
172}