editions.go raw

   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  
   5  package filedesc
   6  
   7  import (
   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  
  16  var (
  17  	defaultsCache = make(map[Edition]EditionFeatures)
  18  	defaultsKeys  = []Edition{}
  19  )
  20  
  21  func 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  
  28  func 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  
  52  func 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  
  96  func 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  
 109  func 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  
 138  func 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  
 160  func 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  }
 173