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