123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // 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 proto
- import (
- "google.golang.org/protobuf/reflect/protoreflect"
- )
- // HasExtension reports whether an extension field is populated.
- // It returns false if m is invalid or if xt does not extend m.
- func HasExtension(m Message, xt protoreflect.ExtensionType) bool {
- // Treat nil message interface or descriptor as an empty message; no populated
- // fields.
- if m == nil || xt == nil {
- return false
- }
- // As a special-case, we reports invalid or mismatching descriptors
- // as always not being populated (since they aren't).
- mr := m.ProtoReflect()
- xd := xt.TypeDescriptor()
- if mr.Descriptor() != xd.ContainingMessage() {
- return false
- }
- return mr.Has(xd)
- }
- // ClearExtension clears an extension field such that subsequent
- // [HasExtension] calls return false.
- // It panics if m is invalid or if xt does not extend m.
- func ClearExtension(m Message, xt protoreflect.ExtensionType) {
- m.ProtoReflect().Clear(xt.TypeDescriptor())
- }
- // GetExtension retrieves the value for an extension field.
- // If the field is unpopulated, it returns the default value for
- // scalars and an immutable, empty value for lists or messages.
- // It panics if xt does not extend m.
- //
- // The type of the value is dependent on the field type of the extension.
- // For extensions generated by protoc-gen-go, the Go type is as follows:
- //
- // ╔═══════════════════╤═════════════════════════╗
- // ║ Go type │ Protobuf kind ║
- // ╠═══════════════════╪═════════════════════════╣
- // ║ bool │ bool ║
- // ║ int32 │ int32, sint32, sfixed32 ║
- // ║ int64 │ int64, sint64, sfixed64 ║
- // ║ uint32 │ uint32, fixed32 ║
- // ║ uint64 │ uint64, fixed64 ║
- // ║ float32 │ float ║
- // ║ float64 │ double ║
- // ║ string │ string ║
- // ║ []byte │ bytes ║
- // ║ protoreflect.Enum │ enum ║
- // ║ proto.Message │ message, group ║
- // ╚═══════════════════╧═════════════════════════╝
- //
- // The protoreflect.Enum and proto.Message types are the concrete Go type
- // associated with the named enum or message. Repeated fields are represented
- // using a Go slice of the base element type.
- //
- // If a generated extension descriptor variable is directly passed to
- // GetExtension, then the call should be followed immediately by a
- // type assertion to the expected output value. For example:
- //
- // mm := proto.GetExtension(m, foopb.E_MyExtension).(*foopb.MyMessage)
- //
- // This pattern enables static analysis tools to verify that the asserted type
- // matches the Go type associated with the extension field and
- // also enables a possible future migration to a type-safe extension API.
- //
- // Since singular messages are the most common extension type, the pattern of
- // calling HasExtension followed by GetExtension may be simplified to:
- //
- // if mm := proto.GetExtension(m, foopb.E_MyExtension).(*foopb.MyMessage); mm != nil {
- // ... // make use of mm
- // }
- //
- // The mm variable is non-nil if and only if HasExtension reports true.
- func GetExtension(m Message, xt protoreflect.ExtensionType) any {
- // Treat nil message interface as an empty message; return the default.
- if m == nil {
- return xt.InterfaceOf(xt.Zero())
- }
- return xt.InterfaceOf(m.ProtoReflect().Get(xt.TypeDescriptor()))
- }
- // SetExtension stores the value of an extension field.
- // It panics if m is invalid, xt does not extend m, or if type of v
- // is invalid for the specified extension field.
- //
- // The type of the value is dependent on the field type of the extension.
- // For extensions generated by protoc-gen-go, the Go type is as follows:
- //
- // ╔═══════════════════╤═════════════════════════╗
- // ║ Go type │ Protobuf kind ║
- // ╠═══════════════════╪═════════════════════════╣
- // ║ bool │ bool ║
- // ║ int32 │ int32, sint32, sfixed32 ║
- // ║ int64 │ int64, sint64, sfixed64 ║
- // ║ uint32 │ uint32, fixed32 ║
- // ║ uint64 │ uint64, fixed64 ║
- // ║ float32 │ float ║
- // ║ float64 │ double ║
- // ║ string │ string ║
- // ║ []byte │ bytes ║
- // ║ protoreflect.Enum │ enum ║
- // ║ proto.Message │ message, group ║
- // ╚═══════════════════╧═════════════════════════╝
- //
- // The protoreflect.Enum and proto.Message types are the concrete Go type
- // associated with the named enum or message. Repeated fields are represented
- // using a Go slice of the base element type.
- //
- // If a generated extension descriptor variable is directly passed to
- // SetExtension (e.g., foopb.E_MyExtension), then the value should be a
- // concrete type that matches the expected Go type for the extension descriptor
- // so that static analysis tools can verify type correctness.
- // This also enables a possible future migration to a type-safe extension API.
- func SetExtension(m Message, xt protoreflect.ExtensionType, v any) {
- xd := xt.TypeDescriptor()
- pv := xt.ValueOf(v)
- // Specially treat an invalid list, map, or message as clear.
- isValid := true
- switch {
- case xd.IsList():
- isValid = pv.List().IsValid()
- case xd.IsMap():
- isValid = pv.Map().IsValid()
- case xd.Message() != nil:
- isValid = pv.Message().IsValid()
- }
- if !isValid {
- m.ProtoReflect().Clear(xd)
- return
- }
- m.ProtoReflect().Set(xd, pv)
- }
- // RangeExtensions iterates over every populated extension field in m in an
- // undefined order, calling f for each extension type and value encountered.
- // It returns immediately if f returns false.
- // While iterating, mutating operations may only be performed
- // on the current extension field.
- func RangeExtensions(m Message, f func(protoreflect.ExtensionType, any) bool) {
- // Treat nil message interface as an empty message; nothing to range over.
- if m == nil {
- return
- }
- m.ProtoReflect().Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- if fd.IsExtension() {
- xt := fd.(protoreflect.ExtensionTypeDescriptor).Type()
- vi := xt.InterfaceOf(v)
- return f(xt, vi)
- }
- return true
- })
- }
|