-
Notifications
You must be signed in to change notification settings - Fork 417
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
internal/filedesc: implement runtime editions support
This change add parsing editions specific descriptor parts to internal/filedesc which makes it possible to load file descriptors of protos using editions at runtime. Change-Id: I7a0c23303acddd2cff115859d4cf82bf0102b14c Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/563615 Reviewed-by: Michael Stapelberg <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
- Loading branch information
Showing
11 changed files
with
415 additions
and
11 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright 2024 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 editiondefaults contains the binary representation of the editions | ||
// defaults. | ||
package editiondefaults | ||
|
||
import _ "embed" | ||
|
||
//go:embed editions_defaults.binpb | ||
var Defaults []byte |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// Copyright 2024 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 filedesc | ||
|
||
import ( | ||
"fmt" | ||
|
||
"google.golang.org/protobuf/encoding/protowire" | ||
"google.golang.org/protobuf/internal/editiondefaults" | ||
"google.golang.org/protobuf/internal/genid" | ||
"google.golang.org/protobuf/reflect/protoreflect" | ||
) | ||
|
||
var defaultsCache = make(map[Edition]EditionFeatures) | ||
|
||
func init() { | ||
unmarshalEditionDefaults(editiondefaults.Defaults) | ||
} | ||
|
||
func unmarshalGoFeature(b []byte, parent EditionFeatures) EditionFeatures { | ||
for len(b) > 0 { | ||
num, _, n := protowire.ConsumeTag(b) | ||
b = b[n:] | ||
switch num { | ||
case genid.GoFeatures_LegacyUnmarshalJsonEnum_field_number: | ||
v, m := protowire.ConsumeVarint(b) | ||
b = b[m:] | ||
parent.GenerateLegacyUnmarshalJSON = protowire.DecodeBool(v) | ||
default: | ||
panic(fmt.Sprintf("unkown field number %d while unmarshalling GoFeatures", num)) | ||
} | ||
} | ||
return parent | ||
} | ||
|
||
func unmarshalFeatureSet(b []byte, parent EditionFeatures) EditionFeatures { | ||
for len(b) > 0 { | ||
num, typ, n := protowire.ConsumeTag(b) | ||
b = b[n:] | ||
switch typ { | ||
case protowire.VarintType: | ||
v, m := protowire.ConsumeVarint(b) | ||
b = b[m:] | ||
switch num { | ||
case genid.FeatureSet_FieldPresence_field_number: | ||
parent.IsFieldPresence = v == genid.FeatureSet_EXPLICIT_enum_value || v == genid.FeatureSet_LEGACY_REQUIRED_enum_value | ||
parent.IsLegacyRequired = v == genid.FeatureSet_LEGACY_REQUIRED_enum_value | ||
case genid.FeatureSet_EnumType_field_number: | ||
parent.IsOpenEnum = v == genid.FeatureSet_OPEN_enum_value | ||
case genid.FeatureSet_RepeatedFieldEncoding_field_number: | ||
parent.IsPacked = v == genid.FeatureSet_PACKED_enum_value | ||
case genid.FeatureSet_Utf8Validation_field_number: | ||
parent.IsUTF8Validated = v == genid.FeatureSet_VERIFY_enum_value | ||
case genid.FeatureSet_MessageEncoding_field_number: | ||
parent.IsDelimitedEncoded = v == genid.FeatureSet_DELIMITED_enum_value | ||
case genid.FeatureSet_JsonFormat_field_number: | ||
parent.IsJSONCompliant = v == genid.FeatureSet_ALLOW_enum_value | ||
default: | ||
panic(fmt.Sprintf("unkown field number %d while unmarshalling FeatureSet", num)) | ||
} | ||
case protowire.BytesType: | ||
v, m := protowire.ConsumeBytes(b) | ||
b = b[m:] | ||
switch num { | ||
case genid.GoFeatures_LegacyUnmarshalJsonEnum_field_number: | ||
parent = unmarshalGoFeature(v, parent) | ||
} | ||
} | ||
} | ||
|
||
return parent | ||
} | ||
|
||
func featuresFromParentDesc(parentDesc protoreflect.Descriptor) EditionFeatures { | ||
var parentFS EditionFeatures | ||
switch p := parentDesc.(type) { | ||
case *File: | ||
parentFS = p.L1.EditionFeatures | ||
case *Message: | ||
parentFS = p.L1.EditionFeatures | ||
default: | ||
panic(fmt.Sprintf("unknown parent type %T", parentDesc)) | ||
} | ||
return parentFS | ||
} | ||
|
||
func unmarshalEditionDefault(b []byte) { | ||
var ed Edition | ||
var fs EditionFeatures | ||
for len(b) > 0 { | ||
num, typ, n := protowire.ConsumeTag(b) | ||
b = b[n:] | ||
switch typ { | ||
case protowire.VarintType: | ||
v, m := protowire.ConsumeVarint(b) | ||
b = b[m:] | ||
switch num { | ||
case genid.FeatureSetDefaults_FeatureSetEditionDefault_Edition_field_number: | ||
ed = Edition(v) | ||
} | ||
case protowire.BytesType: | ||
v, m := protowire.ConsumeBytes(b) | ||
b = b[m:] | ||
switch num { | ||
case genid.FeatureSetDefaults_FeatureSetEditionDefault_Features_field_number: | ||
fs = unmarshalFeatureSet(v, fs) | ||
} | ||
} | ||
} | ||
defaultsCache[ed] = fs | ||
} | ||
|
||
func unmarshalEditionDefaults(b []byte) { | ||
for len(b) > 0 { | ||
num, _, n := protowire.ConsumeTag(b) | ||
b = b[n:] | ||
switch num { | ||
case genid.FeatureSetDefaults_Defaults_field_number: | ||
def, m := protowire.ConsumeBytes(b) | ||
b = b[m:] | ||
unmarshalEditionDefault(def) | ||
case genid.FeatureSetDefaults_MinimumEdition_field_number, | ||
genid.FeatureSetDefaults_MaximumEdition_field_number: | ||
// We don't care about the minimum and maximum editions. If the | ||
// edition we are looking for later on is not in the cache we know | ||
// it is outside of the range between minimum and maximum edition. | ||
_, m := protowire.ConsumeVarint(b) | ||
b = b[m:] | ||
default: | ||
panic(fmt.Sprintf("unkown field number %d while unmarshalling EditionDefault", num)) | ||
} | ||
} | ||
} | ||
|
||
func getFeaturesFor(ed Edition) EditionFeatures { | ||
if def, ok := defaultsCache[ed]; ok { | ||
return def | ||
} | ||
panic(fmt.Sprintf("unsupported edition: %v", ed)) | ||
} |
Oops, something went wrong.