// Go support for Protocol Buffers - Google's data interchange format//// Copyright 2017 The Go Authors. All rights reserved.// https://github.com/golang/protobuf//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.package protoimport ()type generatedDiscarder interface { XXX_DiscardUnknown()}// DiscardUnknown recursively discards all unknown fields from this message// and all embedded messages.//// When unmarshaling a message with unrecognized fields, the tags and values// of such fields are preserved in the Message. This allows a later call to// marshal to be able to produce a message that continues to have those// unrecognized fields. To avoid this, DiscardUnknown is used to// explicitly clear the unknown fields after unmarshaling.//// For proto2 messages, the unknown fields of message extensions are only// discarded from messages that have been accessed via GetExtension.func ( Message) {if , := .(generatedDiscarder); { .XXX_DiscardUnknown()return }// TODO: Dynamically populate a InternalMessageInfo for legacy messages, // but the master branch has no implementation for InternalMessageInfo, // so it would be more work to replicate that approach.discardLegacy()}// DiscardUnknown recursively discards all unknown fields.func ( *InternalMessageInfo) ( Message) { := atomicLoadDiscardInfo(&.discard)if == nil { = getDiscardInfo(reflect.TypeOf().Elem())atomicStoreDiscardInfo(&.discard, ) } .discard(toPointer(&))}type discardInfo struct { typ reflect.Type initialized int32// 0: only typ is valid, 1: everything is valid lock sync.Mutex fields []discardFieldInfo unrecognized field}type discardFieldInfo struct { field field// Offset of field, guaranteed to be valid discard func(src pointer)}var ( discardInfoMap = map[reflect.Type]*discardInfo{} discardInfoLock sync.Mutex)func getDiscardInfo( reflect.Type) *discardInfo {discardInfoLock.Lock()deferdiscardInfoLock.Unlock() := discardInfoMap[]if == nil { = &discardInfo{typ: }discardInfoMap[] = }return}func ( *discardInfo) ( pointer) {if .isNil() {return// Nothing to do. }ifatomic.LoadInt32(&.initialized) == 0 { .computeDiscardInfo() }for , := range .fields { := .offset(.field) .discard() }// For proto2 messages, only discard unknown fields in message extensions // that have been accessed via GetExtension.if , := extendable(.asPointerTo(.typ).Interface()); == nil {// Ignore lock since DiscardUnknown is not concurrency safe. , := .extensionsRead()for , := range {if , := .value.(Message); {DiscardUnknown() } } }if .unrecognized.IsValid() { *.offset(.unrecognized).toBytes() = nil }}func ( *discardInfo) () { .lock.Lock()defer .lock.Unlock()if .initialized != 0 {return } := .typ := .NumField()for := 0; < ; ++ { := .Field()ifstrings.HasPrefix(.Name, "XXX_") {continue } := discardFieldInfo{field: toField(&)} := .Type// Unwrap tf to get its most basic type.var , boolif .Kind() == reflect.Slice && .Elem().Kind() != reflect.Uint8 { = true = .Elem() }if .Kind() == reflect.Ptr { = true = .Elem() }if && && .Kind() != reflect.Struct {panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", , .Name)) }switch .Kind() {casereflect.Struct:switch {case !:panic(fmt.Sprintf("%v.%s cannot be a direct struct value", , .Name))case : // E.g., []*pb.T := getDiscardInfo() .discard = func( pointer) { := .getPointerSlice()for , := range {if !.isNil() { .discard() } } }default: // E.g., *pb.T := getDiscardInfo() .discard = func( pointer) { := .getPointer()if !.isNil() { .discard() } } }casereflect.Map:switch {case || :panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", , .Name))default: // E.g., map[K]Vif .Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T) .discard = func( pointer) { := .asPointerTo().Elem()if .Len() == 0 {return }for , := range .MapKeys() { := .MapIndex()DiscardUnknown(.Interface().(Message)) } } } else { .discard = func(pointer) {} // Noop } }casereflect.Interface:// Must be oneof field.switch {case || :panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", , .Name))default: // E.g., interface{}// TODO: Make this faster? .discard = func( pointer) { := .asPointerTo().Elem()if !.IsNil() { := .Elem().Elem().Field(0)if .Kind() == reflect.Ptr && .IsNil() {return }switch .Type().Kind() {casereflect.Ptr: // Proto struct (e.g., *T)DiscardUnknown(.Interface().(Message)) } } } }default:continue } .fields = append(.fields, ) } .unrecognized = invalidFieldif , := .FieldByName("XXX_unrecognized"); {if .Type != reflect.TypeOf([]byte{}) {panic("expected XXX_unrecognized to be of type []byte") } .unrecognized = toField(&) }atomic.StoreInt32(&.initialized, 1)}func discardLegacy( Message) { := reflect.ValueOf()if .Kind() != reflect.Ptr || .IsNil() {return } = .Elem()if .Kind() != reflect.Struct {return } := .Type()for := 0; < .NumField(); ++ { := .Field()ifstrings.HasPrefix(.Name, "XXX_") {continue } := .Field() := .Type// Unwrap tf to get its most basic type.var , boolif .Kind() == reflect.Slice && .Elem().Kind() != reflect.Uint8 { = true = .Elem() }if .Kind() == reflect.Ptr { = true = .Elem() }if && && .Kind() != reflect.Struct {panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", , .Name)) }switch .Kind() {casereflect.Struct:switch {case !:panic(fmt.Sprintf("%T.%s cannot be a direct struct value", , .Name))case : // E.g., []*pb.Tfor := 0; < .Len(); ++ { (.Index().Interface().(Message)) }default: // E.g., *pb.T (.Interface().(Message)) }casereflect.Map:switch {case || :panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", , .Name))default: // E.g., map[K]V := .Type().Elem()if .Kind() == reflect.Ptr && .Implements(protoMessageType) { // Proto struct (e.g., *T)for , := range .MapKeys() { := .MapIndex() (.Interface().(Message)) } } }casereflect.Interface:// Must be oneof field.switch {case || :panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", , .Name))default: // E.g., test_proto.isCommunique_Union interfaceif !.IsNil() && .Tag.Get("protobuf_oneof") != "" { = .Elem() // E.g., *test_proto.Communique_Msgif !.IsNil() { = .Elem() // E.g., test_proto.Communique_Msg = .Field(0) // E.g., Proto struct (e.g., *T) or primitive valueif .Kind() == reflect.Ptr { (.Interface().(Message)) } } } } } }if := .FieldByName("XXX_unrecognized"); .IsValid() {if .Type() != reflect.TypeOf([]byte{}) {panic("expected XXX_unrecognized to be of type []byte") } .Set(reflect.ValueOf([]byte(nil))) }// For proto2 messages, only discard unknown fields in message extensions // that have been accessed via GetExtension.if , := extendable(); == nil {// Ignore lock since discardLegacy is not concurrency safe. , := .extensionsRead()for , := range {if , := .value.(Message); { () } } }}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.