editions.go

  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}