...

Source file src/google.golang.org/protobuf/proto/extension.go

Documentation: google.golang.org/protobuf/proto

     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 proto
     6  
     7  import (
     8  	"google.golang.org/protobuf/reflect/protoreflect"
     9  )
    10  
    11  // HasExtension reports whether an extension field is populated.
    12  // It returns false if m is invalid or if xt does not extend m.
    13  func HasExtension(m Message, xt protoreflect.ExtensionType) bool {
    14  	// Treat nil message interface or descriptor as an empty message; no populated
    15  	// fields.
    16  	if m == nil || xt == nil {
    17  		return false
    18  	}
    19  
    20  	// As a special-case, we reports invalid or mismatching descriptors
    21  	// as always not being populated (since they aren't).
    22  	mr := m.ProtoReflect()
    23  	xd := xt.TypeDescriptor()
    24  	if mr.Descriptor() != xd.ContainingMessage() {
    25  		return false
    26  	}
    27  
    28  	return mr.Has(xd)
    29  }
    30  
    31  // ClearExtension clears an extension field such that subsequent
    32  // [HasExtension] calls return false.
    33  // It panics if m is invalid or if xt does not extend m.
    34  func ClearExtension(m Message, xt protoreflect.ExtensionType) {
    35  	m.ProtoReflect().Clear(xt.TypeDescriptor())
    36  }
    37  
    38  // GetExtension retrieves the value for an extension field.
    39  // If the field is unpopulated, it returns the default value for
    40  // scalars and an immutable, empty value for lists or messages.
    41  // It panics if xt does not extend m.
    42  func GetExtension(m Message, xt protoreflect.ExtensionType) interface{} {
    43  	// Treat nil message interface as an empty message; return the default.
    44  	if m == nil {
    45  		return xt.InterfaceOf(xt.Zero())
    46  	}
    47  
    48  	return xt.InterfaceOf(m.ProtoReflect().Get(xt.TypeDescriptor()))
    49  }
    50  
    51  // SetExtension stores the value of an extension field.
    52  // It panics if m is invalid, xt does not extend m, or if type of v
    53  // is invalid for the specified extension field.
    54  func SetExtension(m Message, xt protoreflect.ExtensionType, v interface{}) {
    55  	xd := xt.TypeDescriptor()
    56  	pv := xt.ValueOf(v)
    57  
    58  	// Specially treat an invalid list, map, or message as clear.
    59  	isValid := true
    60  	switch {
    61  	case xd.IsList():
    62  		isValid = pv.List().IsValid()
    63  	case xd.IsMap():
    64  		isValid = pv.Map().IsValid()
    65  	case xd.Message() != nil:
    66  		isValid = pv.Message().IsValid()
    67  	}
    68  	if !isValid {
    69  		m.ProtoReflect().Clear(xd)
    70  		return
    71  	}
    72  
    73  	m.ProtoReflect().Set(xd, pv)
    74  }
    75  
    76  // RangeExtensions iterates over every populated extension field in m in an
    77  // undefined order, calling f for each extension type and value encountered.
    78  // It returns immediately if f returns false.
    79  // While iterating, mutating operations may only be performed
    80  // on the current extension field.
    81  func RangeExtensions(m Message, f func(protoreflect.ExtensionType, interface{}) bool) {
    82  	// Treat nil message interface as an empty message; nothing to range over.
    83  	if m == nil {
    84  		return
    85  	}
    86  
    87  	m.ProtoReflect().Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
    88  		if fd.IsExtension() {
    89  			xt := fd.(protoreflect.ExtensionTypeDescriptor).Type()
    90  			vi := xt.InterfaceOf(v)
    91  			return f(xt, vi)
    92  		}
    93  		return true
    94  	})
    95  }
    96  

View as plain text