123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- // Copyright 2019 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package protodesc
- import (
- _ "embed"
- "fmt"
- "os"
- "sync"
- "google.golang.org/protobuf/internal/filedesc"
- "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/types/descriptorpb"
- )
- const (
- SupportedEditionsMinimum = descriptorpb.Edition_EDITION_PROTO2
- SupportedEditionsMaximum = descriptorpb.Edition_EDITION_2023
- )
- //go:embed editions_defaults.binpb
- var binaryEditionDefaults []byte
- var defaults = &descriptorpb.FeatureSetDefaults{}
- var defaultsCacheMu sync.Mutex
- var defaultsCache = make(map[filedesc.Edition]*descriptorpb.FeatureSet)
- func init() {
- err := proto.Unmarshal(binaryEditionDefaults, defaults)
- if err != nil {
- fmt.Fprintf(os.Stderr, "unmarshal editions defaults: %v\n", err)
- os.Exit(1)
- }
- }
- func fromEditionProto(epb descriptorpb.Edition) filedesc.Edition {
- return filedesc.Edition(epb)
- }
- func toEditionProto(ed filedesc.Edition) descriptorpb.Edition {
- switch ed {
- case filedesc.EditionUnknown:
- return descriptorpb.Edition_EDITION_UNKNOWN
- case filedesc.EditionProto2:
- return descriptorpb.Edition_EDITION_PROTO2
- case filedesc.EditionProto3:
- return descriptorpb.Edition_EDITION_PROTO3
- case filedesc.Edition2023:
- return descriptorpb.Edition_EDITION_2023
- default:
- panic(fmt.Sprintf("unknown value for edition: %v", ed))
- }
- }
- func getFeatureSetFor(ed filedesc.Edition) *descriptorpb.FeatureSet {
- defaultsCacheMu.Lock()
- defer defaultsCacheMu.Unlock()
- if def, ok := defaultsCache[ed]; ok {
- return def
- }
- edpb := toEditionProto(ed)
- if defaults.GetMinimumEdition() > edpb || defaults.GetMaximumEdition() < edpb {
- // This should never happen protodesc.(FileOptions).New would fail when
- // initializing the file descriptor.
- // This most likely means the embedded defaults were not updated.
- 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)
- os.Exit(1)
- }
- fs := defaults.GetDefaults()[0].GetFeatures()
- // Using a linear search for now.
- // Editions are guaranteed to be sorted and thus we could use a binary search.
- // Given that there are only a handful of editions (with one more per year)
- // there is not much reason to use a binary search.
- for _, def := range defaults.GetDefaults() {
- if def.GetEdition() <= edpb {
- fs = def.GetFeatures()
- } else {
- break
- }
- }
- defaultsCache[ed] = fs
- return fs
- }
- func resolveFeatureHasFieldPresence(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
- fs := fieldDesc.GetOptions().GetFeatures()
- if fs == nil || fs.FieldPresence == nil {
- return fileDesc.L1.EditionFeatures.IsFieldPresence
- }
- return fs.GetFieldPresence() == descriptorpb.FeatureSet_LEGACY_REQUIRED ||
- fs.GetFieldPresence() == descriptorpb.FeatureSet_EXPLICIT
- }
- func resolveFeatureRepeatedFieldEncodingPacked(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
- fs := fieldDesc.GetOptions().GetFeatures()
- if fs == nil || fs.RepeatedFieldEncoding == nil {
- return fileDesc.L1.EditionFeatures.IsPacked
- }
- return fs.GetRepeatedFieldEncoding() == descriptorpb.FeatureSet_PACKED
- }
- func resolveFeatureEnforceUTF8(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
- fs := fieldDesc.GetOptions().GetFeatures()
- if fs == nil || fs.Utf8Validation == nil {
- return fileDesc.L1.EditionFeatures.IsUTF8Validated
- }
- return fs.GetUtf8Validation() == descriptorpb.FeatureSet_VERIFY
- }
- func resolveFeatureDelimitedEncoding(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
- fs := fieldDesc.GetOptions().GetFeatures()
- if fs == nil || fs.MessageEncoding == nil {
- return fileDesc.L1.EditionFeatures.IsDelimitedEncoded
- }
- return fs.GetMessageEncoding() == descriptorpb.FeatureSet_DELIMITED
- }
- // initFileDescFromFeatureSet initializes editions related fields in fd based
- // on fs. If fs is nil it is assumed to be an empty featureset and all fields
- // will be initialized with the appropriate default. fd.L1.Edition must be set
- // before calling this function.
- func initFileDescFromFeatureSet(fd *filedesc.File, fs *descriptorpb.FeatureSet) {
- dfs := getFeatureSetFor(fd.L1.Edition)
- if fs == nil {
- fs = &descriptorpb.FeatureSet{}
- }
- var fieldPresence descriptorpb.FeatureSet_FieldPresence
- if fp := fs.FieldPresence; fp != nil {
- fieldPresence = *fp
- } else {
- fieldPresence = *dfs.FieldPresence
- }
- fd.L1.EditionFeatures.IsFieldPresence = fieldPresence == descriptorpb.FeatureSet_LEGACY_REQUIRED ||
- fieldPresence == descriptorpb.FeatureSet_EXPLICIT
- var enumType descriptorpb.FeatureSet_EnumType
- if et := fs.EnumType; et != nil {
- enumType = *et
- } else {
- enumType = *dfs.EnumType
- }
- fd.L1.EditionFeatures.IsOpenEnum = enumType == descriptorpb.FeatureSet_OPEN
- var respeatedFieldEncoding descriptorpb.FeatureSet_RepeatedFieldEncoding
- if rfe := fs.RepeatedFieldEncoding; rfe != nil {
- respeatedFieldEncoding = *rfe
- } else {
- respeatedFieldEncoding = *dfs.RepeatedFieldEncoding
- }
- fd.L1.EditionFeatures.IsPacked = respeatedFieldEncoding == descriptorpb.FeatureSet_PACKED
- var isUTF8Validated descriptorpb.FeatureSet_Utf8Validation
- if utf8val := fs.Utf8Validation; utf8val != nil {
- isUTF8Validated = *utf8val
- } else {
- isUTF8Validated = *dfs.Utf8Validation
- }
- fd.L1.EditionFeatures.IsUTF8Validated = isUTF8Validated == descriptorpb.FeatureSet_VERIFY
- var messageEncoding descriptorpb.FeatureSet_MessageEncoding
- if me := fs.MessageEncoding; me != nil {
- messageEncoding = *me
- } else {
- messageEncoding = *dfs.MessageEncoding
- }
- fd.L1.EditionFeatures.IsDelimitedEncoded = messageEncoding == descriptorpb.FeatureSet_DELIMITED
- var jsonFormat descriptorpb.FeatureSet_JsonFormat
- if jf := fs.JsonFormat; jf != nil {
- jsonFormat = *jf
- } else {
- jsonFormat = *dfs.JsonFormat
- }
- fd.L1.EditionFeatures.IsJSONCompliant = jsonFormat == descriptorpb.FeatureSet_ALLOW
- }
|