// Go support for Protocol Buffers - Google's data interchange format//// Copyright 2010 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 proto/* * Types and routines for supporting protocol buffer extensions. */import ()// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message.varErrMissingExtension = errors.New("proto: missing extension")// ExtensionRange represents a range of message extensions for a protocol buffer.// Used in code generated by the protocol compiler.typeExtensionRangestruct { Start, End int32// both inclusive}// extendableProto is an interface implemented by any protocol buffer generated by the current// proto compiler that may be extended.type extendableProto interface {Message ExtensionRangeArray() []ExtensionRange extensionsWrite() map[int32]Extension extensionsRead() (map[int32]Extension, sync.Locker)}// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous// version of the proto compiler that may be extended.type extendableProtoV1 interface {Message ExtensionRangeArray() []ExtensionRange ExtensionMap() map[int32]Extension}// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto.type extensionAdapter struct {extendableProtoV1}func ( extensionAdapter) () map[int32]Extension {return .ExtensionMap()}func ( extensionAdapter) () (map[int32]Extension, sync.Locker) {return .ExtensionMap(), notLocker{}}// notLocker is a sync.Locker whose Lock and Unlock methods are nops.type notLocker struct{}func ( notLocker) () {}func ( notLocker) () {}// extendable returns the extendableProto interface for the given generated proto message.// If the proto message has the old extension format, it returns a wrapper that implements// the extendableProto interface.func extendable( interface{}) (extendableProto, error) {switch p := .(type) {caseextendableProto:ifisNilPtr() {returnnil, fmt.Errorf("proto: nil %T is not extendable", ) }return , nilcaseextendableProtoV1:ifisNilPtr() {returnnil, fmt.Errorf("proto: nil %T is not extendable", ) }returnextensionAdapter{}, nilcaseextensionsBytes:returnslowExtensionAdapter{}, nil }// Don't allocate a specific error containing %T: // this is the hot path for Clone and MarshalText.returnnil, errNotExtendable}var errNotExtendable = errors.New("proto: not an extendable proto.Message")func isNilPtr( interface{}) bool { := reflect.ValueOf()return .Kind() == reflect.Ptr && .IsNil()}// XXX_InternalExtensions is an internal representation of proto extensions.//// Each generated message struct type embeds an anonymous XXX_InternalExtensions field,// thus gaining the unexported 'extensions' method, which can be called only from the proto package.//// The methods of XXX_InternalExtensions are not concurrency safe in general,// but calls to logically read-only methods such as has and get may be executed concurrently.typeXXX_InternalExtensionsstruct {// The struct must be indirect so that if a user inadvertently copies a // generated message and its embedded XXX_InternalExtensions, they // avoid the mayhem of a copied mutex. // // The mutex serializes all logically read-only operations to p.extensionMap. // It is up to the client to ensure that write operations to p.extensionMap are // mutually exclusive with other accesses. p *struct { mu sync.Mutex extensionMap map[int32]Extension }}// extensionsWrite returns the extension map, creating it on first use.func ( *XXX_InternalExtensions) () map[int32]Extension {if .p == nil { .p = new(struct {sync.Mutexmap[int32]Extension }) .p.extensionMap = make(map[int32]Extension) }return .p.extensionMap}// extensionsRead returns the extensions map for read-only use. It may be nil.// The caller must hold the returned mutex's lock when accessing Elements within the map.func ( *XXX_InternalExtensions) () (map[int32]Extension, sync.Locker) {if .p == nil {returnnil, nil }return .p.extensionMap, &.p.mu}// ExtensionDesc represents an extension specification.// Used in generated code from the protocol compiler.typeExtensionDescstruct { ExtendedType Message// nil pointer to the type that is being extended ExtensionType interface{} // nil pointer to the extension type Field int32// field number Name string// fully-qualified name of extension, for text formatting Tag string// protobuf tag style Filename string// name of the file in which the extension is defined}func ( *ExtensionDesc) () bool { := reflect.TypeOf(.ExtensionType)return .Kind() == reflect.Slice && .Elem().Kind() != reflect.Uint8}// Extension represents an extension in a message.typeExtensionstruct {// When an extension is stored in a message using SetExtension // only desc and value are set. When the message is marshaled // enc will be set to the encoded form of the message. // // When a message is unmarshaled and contains extensions, each // extension will have only enc set. When such an extension is // accessed using GetExtension (or GetExtensions) desc and value // will be set. desc *ExtensionDesc value interface{} enc []byte}// SetRawExtension is for testing only.func ( Message, int32, []byte) {if , := .(extensionsBytes); {clearExtension(, ) := .GetExtensions() * = append(*, ...)return } , := extendable()if != nil {return } := .extensionsWrite() [] = Extension{enc: }}// isExtensionField returns true iff the given field number is in an extension range.func isExtensionField( extendableProto, int32) bool {for , := range .ExtensionRangeArray() {if .Start <= && <= .End {returntrue } }returnfalse}// checkExtensionTypes checks that the given extension is valid for pb.func checkExtensionTypes( extendableProto, *ExtensionDesc) error {varinterface{} = // Check the extended type.if , := .(extensionAdapter); { = .extendableProtoV1 }if , := .(slowExtensionAdapter); { = .extensionsBytes }if , := reflect.TypeOf(), reflect.TypeOf(.ExtendedType); != {returnfmt.Errorf("proto: bad extended type; %v does not extend %v", , ) }// Check the range.if !isExtensionField(, .Field) {returnerrors.New("proto: bad extension number; not in declared ranges") }returnnil}// extPropKey is sufficient to uniquely identify an extension.type extPropKey struct { base reflect.Type field int32}var extProp = struct {sync.RWMutex m map[extPropKey]*Properties}{m: make(map[extPropKey]*Properties),}func extensionProperties( *ExtensionDesc) *Properties { := extPropKey{base: reflect.TypeOf(.ExtendedType), field: .Field}extProp.RLock()if , := extProp.m[]; {extProp.RUnlock()return }extProp.RUnlock()extProp.Lock()deferextProp.Unlock()// Check again.if , := extProp.m[]; {return } := new(Properties) .Init(reflect.TypeOf(.ExtensionType), "unknown_name", .Tag, nil)extProp.m[] = return}// HasExtension returns whether the given extension is present in pb.func ( Message, *ExtensionDesc) bool {if , := .(extensionsBytes); { := .GetExtensions() := * := 0for < len() { , := DecodeVarint([:]) := int32( >> 3)ifint32() == .Field {returntrue } := int( & 0x7) += , := size([:], )if != nil {returnfalse } += }returnfalse }// TODO: Check types, field numbers, etc.? , := extendable()if != nil {returnfalse } , := .extensionsRead()if == nil {returnfalse } .Lock() , := [.Field] .Unlock()return}// ClearExtension removes the given extension from pb.func ( Message, *ExtensionDesc) {clearExtension(, .Field)}func clearExtension( Message, int32) {if , := .(extensionsBytes); { := 0for != -1 { = deleteExtension(, , ) }return } , := extendable()if != nil {return }// TODO: Check types, field numbers, etc.? := .extensionsWrite()delete(, )}// GetExtension retrieves a proto2 extended field from pb.//// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),// then GetExtension parses the encoded field and returns a Go value of the specified type.// If the field is not present, then the default value is returned (if one is specified),// otherwise ErrMissingExtension is reported.//// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil),// then GetExtension returns the raw encoded bytes of the field extension.func ( Message, *ExtensionDesc) (interface{}, error) {if , := .(extensionsBytes); { := .GetExtensions()returndecodeExtensionFromBytes(, *) } , := extendable()if != nil {returnnil, }if .ExtendedType != nil {// can only check type if this is a complete descriptorif := checkExtensionTypes(, ); != nil {returnnil, } } , := .extensionsRead()if == nil {returndefaultExtensionValue() } .Lock()defer .Unlock() , := [.Field]if ! {// defaultExtensionValue returns the default value or // ErrMissingExtension if there is no default.returndefaultExtensionValue() }if .value != nil {// Already decoded. Check the descriptor, though.if .desc != {// This shouldn't happen. If it does, it means that // GetExtension was called twice with two different // descriptors with the same field number.returnnil, errors.New("proto: descriptor conflict") }return .value, nil }if .ExtensionType == nil {// incomplete descriptorreturn .enc, nil } , := decodeExtension(.enc, )if != nil {returnnil, }// Remember the decoded version and drop the encoded version. // That way it is safe to mutate what we return. .value = .desc = .enc = nil [.Field] = return .value, nil}// defaultExtensionValue returns the default value for extension.// If no default for an extension is defined ErrMissingExtension is returned.func defaultExtensionValue( *ExtensionDesc) (interface{}, error) {if .ExtensionType == nil {// incomplete descriptor, so no defaultreturnnil, ErrMissingExtension } := reflect.TypeOf(.ExtensionType) := extensionProperties() , , := fieldDefault(, )if != nil {returnnil, }if == nil || .value == nil {// There is no default value.returnnil, ErrMissingExtension }if .Kind() != reflect.Ptr {// We do not need to return a Ptr, we can directly return sf.value.return .value, nil }// We need to return an interface{} that is a pointer to sf.value. := reflect.New().Elem() .Set(reflect.New(.Type().Elem()))if .kind == reflect.Int32 {// We may have an int32 or an enum, but the underlying data is int32. // Since we can't set an int32 into a non int32 reflect.value directly // set it as a int32. .Elem().SetInt(int64(.value.(int32))) } else { .Elem().Set(reflect.ValueOf(.value)) }return .Interface(), nil}// decodeExtension decodes an extension encoded in b.func decodeExtension( []byte, *ExtensionDesc) (interface{}, error) { := reflect.TypeOf(.ExtensionType) := typeUnmarshaler(, .Tag)// t is a pointer to a struct, pointer to basic type or a slice. // Allocate space to store the pointer/slice. := reflect.New().Elem()varerrorfor { , := decodeVarint()if == 0 {returnnil, io.ErrUnexpectedEOF } = [:] := int() & 7 , = (, valToPointer(.Addr()), )if != nil {returnnil, }iflen() == 0 {break } }return .Interface(), nil}// GetExtensions returns a slice of the extensions present in pb that are also listed in es.// The returned slice has the same length as es; missing extensions will appear as nil elements.func ( Message, []*ExtensionDesc) ( []interface{}, error) { , := extendable()if != nil {returnnil, } = make([]interface{}, len())for , := range { [], = GetExtension(, )if == ErrMissingExtension { = nil }if != nil {return } }return}// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order.// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing// just the Field field, which defines the extension's field number.func ( Message) ([]*ExtensionDesc, error) { , := extendable()if != nil {returnnil, } := RegisteredExtensions() , := .extensionsRead()if == nil {returnnil, nil } .Lock()defer .Unlock() := make([]*ExtensionDesc, 0, len())for , := range { := .descif == nil { = []if == nil { = &ExtensionDesc{Field: } } } = append(, ) }return , nil}// SetExtension sets the specified extension of pb to the specified value.func ( Message, *ExtensionDesc, interface{}) error {if , := .(extensionsBytes); {ClearExtension(, ) , := encodeExtension(, )if != nil {return } := .GetExtensions() * = append(*, ...)returnnil } , := extendable()if != nil {return }if := checkExtensionTypes(, ); != nil {return } := reflect.TypeOf(.ExtensionType)if != reflect.TypeOf() {returnfmt.Errorf("proto: bad extension value type. got: %T, want: %T", , .ExtensionType) }// nil extension values need to be caught early, because the // encoder can't distinguish an ErrNil due to a nil extension // from an ErrNil due to a missing field. Extensions are // always optional, so the encoder would just swallow the error // and drop all the extensions from the encoded message.ifreflect.ValueOf().IsNil() {returnfmt.Errorf("proto: SetExtension called with nil value of type %T", ) } := .extensionsWrite() [.Field] = Extension{desc: , value: }returnnil}// ClearAllExtensions clears all extensions from pb.func ( Message) {if , := .(extensionsBytes); { := .GetExtensions() * = []byte{}return } , := extendable()if != nil {return } := .extensionsWrite()for := range {delete(, ) }}// A global registry of extensions.// The generated code will register the generated descriptors by calling RegisterExtension.var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)// RegisterExtension is called from the generated code.func ( *ExtensionDesc) { := reflect.TypeOf(.ExtendedType).Elem() := extensionMaps[]if == nil { = make(map[int32]*ExtensionDesc)extensionMaps[] = }if , := [.Field]; {panic("proto: duplicate extension registered: " + .String() + " " + strconv.Itoa(int(.Field))) } [.Field] = }// RegisteredExtensions returns a map of the registered extensions of a// protocol buffer struct, indexed by the extension number.// The argument pb should be a nil pointer to the struct type.func ( Message) map[int32]*ExtensionDesc {returnextensionMaps[reflect.TypeOf().Elem()]}
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.