...

Source file src/google.golang.org/protobuf/reflect/protodesc/editions.go

Documentation: google.golang.org/protobuf/reflect/protodesc

     1  // Copyright 2019 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 protodesc
     6  
     7  import (
     8  	_ "embed"
     9  	"fmt"
    10  	"os"
    11  	"sync"
    12  
    13  	"google.golang.org/protobuf/internal/filedesc"
    14  	"google.golang.org/protobuf/proto"
    15  	"google.golang.org/protobuf/types/descriptorpb"
    16  )
    17  
    18  const (
    19  	SupportedEditionsMinimum = descriptorpb.Edition_EDITION_PROTO2
    20  	SupportedEditionsMaximum = descriptorpb.Edition_EDITION_2023
    21  )
    22  
    23  //go:embed editions_defaults.binpb
    24  var binaryEditionDefaults []byte
    25  var defaults = &descriptorpb.FeatureSetDefaults{}
    26  var defaultsCacheMu sync.Mutex
    27  var defaultsCache = make(map[filedesc.Edition]*descriptorpb.FeatureSet)
    28  
    29  func init() {
    30  	err := proto.Unmarshal(binaryEditionDefaults, defaults)
    31  	if err != nil {
    32  		fmt.Fprintf(os.Stderr, "unmarshal editions defaults: %v\n", err)
    33  		os.Exit(1)
    34  	}
    35  }
    36  
    37  func fromEditionProto(epb descriptorpb.Edition) filedesc.Edition {
    38  	return filedesc.Edition(epb)
    39  }
    40  
    41  func toEditionProto(ed filedesc.Edition) descriptorpb.Edition {
    42  	switch ed {
    43  	case filedesc.EditionUnknown:
    44  		return descriptorpb.Edition_EDITION_UNKNOWN
    45  	case filedesc.EditionProto2:
    46  		return descriptorpb.Edition_EDITION_PROTO2
    47  	case filedesc.EditionProto3:
    48  		return descriptorpb.Edition_EDITION_PROTO3
    49  	case filedesc.Edition2023:
    50  		return descriptorpb.Edition_EDITION_2023
    51  	default:
    52  		panic(fmt.Sprintf("unknown value for edition: %v", ed))
    53  	}
    54  }
    55  
    56  func getFeatureSetFor(ed filedesc.Edition) *descriptorpb.FeatureSet {
    57  	defaultsCacheMu.Lock()
    58  	defer defaultsCacheMu.Unlock()
    59  	if def, ok := defaultsCache[ed]; ok {
    60  		return def
    61  	}
    62  	edpb := toEditionProto(ed)
    63  	if defaults.GetMinimumEdition() > edpb || defaults.GetMaximumEdition() < edpb {
    64  		// This should never happen protodesc.(FileOptions).New would fail when
    65  		// initializing the file descriptor.
    66  		// This most likely means the embedded defaults were not updated.
    67  		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)
    68  		os.Exit(1)
    69  	}
    70  	fs := defaults.GetDefaults()[0].GetFeatures()
    71  	// Using a linear search for now.
    72  	// Editions are guaranteed to be sorted and thus we could use a binary search.
    73  	// Given that there are only a handful of editions (with one more per year)
    74  	// there is not much reason to use a binary search.
    75  	for _, def := range defaults.GetDefaults() {
    76  		if def.GetEdition() <= edpb {
    77  			fs = def.GetFeatures()
    78  		} else {
    79  			break
    80  		}
    81  	}
    82  	defaultsCache[ed] = fs
    83  	return fs
    84  }
    85  
    86  func resolveFeatureHasFieldPresence(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
    87  	fs := fieldDesc.GetOptions().GetFeatures()
    88  	if fs == nil || fs.FieldPresence == nil {
    89  		return fileDesc.L1.EditionFeatures.IsFieldPresence
    90  	}
    91  	return fs.GetFieldPresence() == descriptorpb.FeatureSet_LEGACY_REQUIRED ||
    92  		fs.GetFieldPresence() == descriptorpb.FeatureSet_EXPLICIT
    93  }
    94  
    95  func resolveFeatureRepeatedFieldEncodingPacked(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
    96  	fs := fieldDesc.GetOptions().GetFeatures()
    97  	if fs == nil || fs.RepeatedFieldEncoding == nil {
    98  		return fileDesc.L1.EditionFeatures.IsPacked
    99  	}
   100  	return fs.GetRepeatedFieldEncoding() == descriptorpb.FeatureSet_PACKED
   101  }
   102  
   103  func resolveFeatureEnforceUTF8(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
   104  	fs := fieldDesc.GetOptions().GetFeatures()
   105  	if fs == nil || fs.Utf8Validation == nil {
   106  		return fileDesc.L1.EditionFeatures.IsUTF8Validated
   107  	}
   108  	return fs.GetUtf8Validation() == descriptorpb.FeatureSet_VERIFY
   109  }
   110  
   111  func resolveFeatureDelimitedEncoding(fileDesc *filedesc.File, fieldDesc *descriptorpb.FieldDescriptorProto) bool {
   112  	fs := fieldDesc.GetOptions().GetFeatures()
   113  	if fs == nil || fs.MessageEncoding == nil {
   114  		return fileDesc.L1.EditionFeatures.IsDelimitedEncoded
   115  	}
   116  	return fs.GetMessageEncoding() == descriptorpb.FeatureSet_DELIMITED
   117  }
   118  
   119  // initFileDescFromFeatureSet initializes editions related fields in fd based
   120  // on fs. If fs is nil it is assumed to be an empty featureset and all fields
   121  // will be initialized with the appropriate default. fd.L1.Edition must be set
   122  // before calling this function.
   123  func initFileDescFromFeatureSet(fd *filedesc.File, fs *descriptorpb.FeatureSet) {
   124  	dfs := getFeatureSetFor(fd.L1.Edition)
   125  	if fs == nil {
   126  		fs = &descriptorpb.FeatureSet{}
   127  	}
   128  
   129  	var fieldPresence descriptorpb.FeatureSet_FieldPresence
   130  	if fp := fs.FieldPresence; fp != nil {
   131  		fieldPresence = *fp
   132  	} else {
   133  		fieldPresence = *dfs.FieldPresence
   134  	}
   135  	fd.L1.EditionFeatures.IsFieldPresence = fieldPresence == descriptorpb.FeatureSet_LEGACY_REQUIRED ||
   136  		fieldPresence == descriptorpb.FeatureSet_EXPLICIT
   137  
   138  	var enumType descriptorpb.FeatureSet_EnumType
   139  	if et := fs.EnumType; et != nil {
   140  		enumType = *et
   141  	} else {
   142  		enumType = *dfs.EnumType
   143  	}
   144  	fd.L1.EditionFeatures.IsOpenEnum = enumType == descriptorpb.FeatureSet_OPEN
   145  
   146  	var respeatedFieldEncoding descriptorpb.FeatureSet_RepeatedFieldEncoding
   147  	if rfe := fs.RepeatedFieldEncoding; rfe != nil {
   148  		respeatedFieldEncoding = *rfe
   149  	} else {
   150  		respeatedFieldEncoding = *dfs.RepeatedFieldEncoding
   151  	}
   152  	fd.L1.EditionFeatures.IsPacked = respeatedFieldEncoding == descriptorpb.FeatureSet_PACKED
   153  
   154  	var isUTF8Validated descriptorpb.FeatureSet_Utf8Validation
   155  	if utf8val := fs.Utf8Validation; utf8val != nil {
   156  		isUTF8Validated = *utf8val
   157  	} else {
   158  		isUTF8Validated = *dfs.Utf8Validation
   159  	}
   160  	fd.L1.EditionFeatures.IsUTF8Validated = isUTF8Validated == descriptorpb.FeatureSet_VERIFY
   161  
   162  	var messageEncoding descriptorpb.FeatureSet_MessageEncoding
   163  	if me := fs.MessageEncoding; me != nil {
   164  		messageEncoding = *me
   165  	} else {
   166  		messageEncoding = *dfs.MessageEncoding
   167  	}
   168  	fd.L1.EditionFeatures.IsDelimitedEncoded = messageEncoding == descriptorpb.FeatureSet_DELIMITED
   169  
   170  	var jsonFormat descriptorpb.FeatureSet_JsonFormat
   171  	if jf := fs.JsonFormat; jf != nil {
   172  		jsonFormat = *jf
   173  	} else {
   174  		jsonFormat = *dfs.JsonFormat
   175  	}
   176  	fd.L1.EditionFeatures.IsJSONCompliant = jsonFormat == descriptorpb.FeatureSet_ALLOW
   177  }
   178  

View as plain text