mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			149 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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 (
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"sync"
 | 
						|
 | 
						|
	"google.golang.org/protobuf/internal/editiondefaults"
 | 
						|
	"google.golang.org/protobuf/internal/filedesc"
 | 
						|
	"google.golang.org/protobuf/proto"
 | 
						|
	"google.golang.org/protobuf/reflect/protoreflect"
 | 
						|
	"google.golang.org/protobuf/types/descriptorpb"
 | 
						|
	gofeaturespb "google.golang.org/protobuf/types/gofeaturespb"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	SupportedEditionsMinimum = descriptorpb.Edition_EDITION_PROTO2
 | 
						|
	SupportedEditionsMaximum = descriptorpb.Edition_EDITION_2023
 | 
						|
)
 | 
						|
 | 
						|
var defaults = &descriptorpb.FeatureSetDefaults{}
 | 
						|
var defaultsCacheMu sync.Mutex
 | 
						|
var defaultsCache = make(map[filedesc.Edition]*descriptorpb.FeatureSet)
 | 
						|
 | 
						|
func init() {
 | 
						|
	err := proto.Unmarshal(editiondefaults.Defaults, 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
 | 
						|
}
 | 
						|
 | 
						|
// mergeEditionFeatures merges the parent and child feature sets. This function
 | 
						|
// should be used when initializing Go descriptors from descriptor protos which
 | 
						|
// is why the parent is a filedesc.EditionsFeatures (Go representation) while
 | 
						|
// the child is a descriptorproto.FeatureSet (protoc representation).
 | 
						|
// Any feature set by the child overwrites what is set by the parent.
 | 
						|
func mergeEditionFeatures(parentDesc protoreflect.Descriptor, child *descriptorpb.FeatureSet) filedesc.EditionFeatures {
 | 
						|
	var parentFS filedesc.EditionFeatures
 | 
						|
	switch p := parentDesc.(type) {
 | 
						|
	case *filedesc.File:
 | 
						|
		parentFS = p.L1.EditionFeatures
 | 
						|
	case *filedesc.Message:
 | 
						|
		parentFS = p.L1.EditionFeatures
 | 
						|
	default:
 | 
						|
		panic(fmt.Sprintf("unknown parent type %T", parentDesc))
 | 
						|
	}
 | 
						|
	if child == nil {
 | 
						|
		return parentFS
 | 
						|
	}
 | 
						|
	if fp := child.FieldPresence; fp != nil {
 | 
						|
		parentFS.IsFieldPresence = *fp == descriptorpb.FeatureSet_LEGACY_REQUIRED ||
 | 
						|
			*fp == descriptorpb.FeatureSet_EXPLICIT
 | 
						|
		parentFS.IsLegacyRequired = *fp == descriptorpb.FeatureSet_LEGACY_REQUIRED
 | 
						|
	}
 | 
						|
	if et := child.EnumType; et != nil {
 | 
						|
		parentFS.IsOpenEnum = *et == descriptorpb.FeatureSet_OPEN
 | 
						|
	}
 | 
						|
 | 
						|
	if rfe := child.RepeatedFieldEncoding; rfe != nil {
 | 
						|
		parentFS.IsPacked = *rfe == descriptorpb.FeatureSet_PACKED
 | 
						|
	}
 | 
						|
 | 
						|
	if utf8val := child.Utf8Validation; utf8val != nil {
 | 
						|
		parentFS.IsUTF8Validated = *utf8val == descriptorpb.FeatureSet_VERIFY
 | 
						|
	}
 | 
						|
 | 
						|
	if me := child.MessageEncoding; me != nil {
 | 
						|
		parentFS.IsDelimitedEncoded = *me == descriptorpb.FeatureSet_DELIMITED
 | 
						|
	}
 | 
						|
 | 
						|
	if jf := child.JsonFormat; jf != nil {
 | 
						|
		parentFS.IsJSONCompliant = *jf == descriptorpb.FeatureSet_ALLOW
 | 
						|
	}
 | 
						|
 | 
						|
	if goFeatures, ok := proto.GetExtension(child, gofeaturespb.E_Go).(*gofeaturespb.GoFeatures); ok && goFeatures != nil {
 | 
						|
		if luje := goFeatures.LegacyUnmarshalJsonEnum; luje != nil {
 | 
						|
			parentFS.GenerateLegacyUnmarshalJSON = *luje
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return parentFS
 | 
						|
}
 | 
						|
 | 
						|
// 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)
 | 
						|
	// initialize the featureset with the defaults
 | 
						|
	fd.L1.EditionFeatures = mergeEditionFeatures(fd, dfs)
 | 
						|
	// overwrite any options explicitly specified
 | 
						|
	fd.L1.EditionFeatures = mergeEditionFeatures(fd, fs)
 | 
						|
}
 |