package impl
import (
"fmt"
"math"
"reflect"
"google.golang.org/protobuf/reflect/protoreflect"
)
type fieldInfo struct {
fieldDesc protoreflect .FieldDescriptor
has func (pointer ) bool
clear func (pointer )
get func (pointer ) protoreflect .Value
set func (pointer , protoreflect .Value )
mutable func (pointer ) protoreflect .Value
newMessage func () protoreflect .Message
newField func () protoreflect .Value
}
func fieldInfoForMissing(fd protoreflect .FieldDescriptor ) fieldInfo {
return fieldInfo {
fieldDesc : fd ,
has : func (p pointer ) bool {
return false
},
clear : func (p pointer ) {
panic ("missing Go struct field for " + string (fd .FullName ()))
},
get : func (p pointer ) protoreflect .Value {
return fd .Default ()
},
set : func (p pointer , v protoreflect .Value ) {
panic ("missing Go struct field for " + string (fd .FullName ()))
},
mutable : func (p pointer ) protoreflect .Value {
panic ("missing Go struct field for " + string (fd .FullName ()))
},
newMessage : func () protoreflect .Message {
panic ("missing Go struct field for " + string (fd .FullName ()))
},
newField : func () protoreflect .Value {
if v := fd .Default (); v .IsValid () {
return v
}
panic ("missing Go struct field for " + string (fd .FullName ()))
},
}
}
func fieldInfoForOneof(fd protoreflect .FieldDescriptor , fs reflect .StructField , x exporter , ot reflect .Type ) fieldInfo {
ft := fs .Type
if ft .Kind () != reflect .Interface {
panic (fmt .Sprintf ("field %v has invalid type: got %v, want interface kind" , fd .FullName (), ft ))
}
if ot .Kind () != reflect .Struct {
panic (fmt .Sprintf ("field %v has invalid type: got %v, want struct kind" , fd .FullName (), ot ))
}
if !reflect .PtrTo (ot ).Implements (ft ) {
panic (fmt .Sprintf ("field %v has invalid type: %v does not implement %v" , fd .FullName (), ot , ft ))
}
conv := NewConverter (ot .Field (0 ).Type , fd )
isMessage := fd .Message () != nil
fieldOffset := offsetOf (fs )
return fieldInfo {
fieldDesc : fd ,
has : func (p pointer ) bool {
if p .IsNil () {
return false
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if rv .IsNil () || rv .Elem ().Type ().Elem () != ot || rv .Elem ().IsNil () {
return false
}
return true
},
clear : func (p pointer ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if rv .IsNil () || rv .Elem ().Type ().Elem () != ot {
return
}
rv .Set (reflect .Zero (rv .Type ()))
},
get : func (p pointer ) protoreflect .Value {
if p .IsNil () {
return conv .Zero ()
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if rv .IsNil () || rv .Elem ().Type ().Elem () != ot || rv .Elem ().IsNil () {
return conv .Zero ()
}
rv = rv .Elem ().Elem ().Field (0 )
return conv .PBValueOf (rv )
},
set : func (p pointer , v protoreflect .Value ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if rv .IsNil () || rv .Elem ().Type ().Elem () != ot || rv .Elem ().IsNil () {
rv .Set (reflect .New (ot ))
}
rv = rv .Elem ().Elem ().Field (0 )
rv .Set (conv .GoValueOf (v ))
},
mutable : func (p pointer ) protoreflect .Value {
if !isMessage {
panic (fmt .Sprintf ("field %v with invalid Mutable call on field with non-composite type" , fd .FullName ()))
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if rv .IsNil () || rv .Elem ().Type ().Elem () != ot || rv .Elem ().IsNil () {
rv .Set (reflect .New (ot ))
}
rv = rv .Elem ().Elem ().Field (0 )
if rv .Kind () == reflect .Ptr && rv .IsNil () {
rv .Set (conv .GoValueOf (protoreflect .ValueOfMessage (conv .New ().Message ())))
}
return conv .PBValueOf (rv )
},
newMessage : func () protoreflect .Message {
return conv .New ().Message ()
},
newField : func () protoreflect .Value {
return conv .New ()
},
}
}
func fieldInfoForMap(fd protoreflect .FieldDescriptor , fs reflect .StructField , x exporter ) fieldInfo {
ft := fs .Type
if ft .Kind () != reflect .Map {
panic (fmt .Sprintf ("field %v has invalid type: got %v, want map kind" , fd .FullName (), ft ))
}
conv := NewConverter (ft , fd )
fieldOffset := offsetOf (fs )
return fieldInfo {
fieldDesc : fd ,
has : func (p pointer ) bool {
if p .IsNil () {
return false
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
return rv .Len () > 0
},
clear : func (p pointer ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
rv .Set (reflect .Zero (rv .Type ()))
},
get : func (p pointer ) protoreflect .Value {
if p .IsNil () {
return conv .Zero ()
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if rv .Len () == 0 {
return conv .Zero ()
}
return conv .PBValueOf (rv )
},
set : func (p pointer , v protoreflect .Value ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
pv := conv .GoValueOf (v )
if pv .IsNil () {
panic (fmt .Sprintf ("map field %v cannot be set with read-only value" , fd .FullName ()))
}
rv .Set (pv )
},
mutable : func (p pointer ) protoreflect .Value {
v := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if v .IsNil () {
v .Set (reflect .MakeMap (fs .Type ))
}
return conv .PBValueOf (v )
},
newField : func () protoreflect .Value {
return conv .New ()
},
}
}
func fieldInfoForList(fd protoreflect .FieldDescriptor , fs reflect .StructField , x exporter ) fieldInfo {
ft := fs .Type
if ft .Kind () != reflect .Slice {
panic (fmt .Sprintf ("field %v has invalid type: got %v, want slice kind" , fd .FullName (), ft ))
}
conv := NewConverter (reflect .PtrTo (ft ), fd )
fieldOffset := offsetOf (fs )
return fieldInfo {
fieldDesc : fd ,
has : func (p pointer ) bool {
if p .IsNil () {
return false
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
return rv .Len () > 0
},
clear : func (p pointer ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
rv .Set (reflect .Zero (rv .Type ()))
},
get : func (p pointer ) protoreflect .Value {
if p .IsNil () {
return conv .Zero ()
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type )
if rv .Elem ().Len () == 0 {
return conv .Zero ()
}
return conv .PBValueOf (rv )
},
set : func (p pointer , v protoreflect .Value ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
pv := conv .GoValueOf (v )
if pv .IsNil () {
panic (fmt .Sprintf ("list field %v cannot be set with read-only value" , fd .FullName ()))
}
rv .Set (pv .Elem ())
},
mutable : func (p pointer ) protoreflect .Value {
v := p .Apply (fieldOffset ).AsValueOf (fs .Type )
return conv .PBValueOf (v )
},
newField : func () protoreflect .Value {
return conv .New ()
},
}
}
var (
nilBytes = reflect .ValueOf ([]byte (nil ))
emptyBytes = reflect .ValueOf ([]byte {})
)
func fieldInfoForScalar(fd protoreflect .FieldDescriptor , fs reflect .StructField , x exporter ) fieldInfo {
ft := fs .Type
nullable := fd .HasPresence ()
isBytes := ft .Kind () == reflect .Slice && ft .Elem ().Kind () == reflect .Uint8
var getter func (p pointer ) protoreflect .Value
if nullable {
if ft .Kind () != reflect .Ptr && ft .Kind () != reflect .Slice {
nullable = false
}
if ft .Kind () == reflect .Ptr {
ft = ft .Elem ()
}
}
conv := NewConverter (ft , fd )
fieldOffset := offsetOf (fs )
if nullable {
getter = getterForNullableScalar (fd , fs , conv , fieldOffset )
} else {
getter = getterForDirectScalar (fd , fs , conv , fieldOffset )
}
return fieldInfo {
fieldDesc : fd ,
has : func (p pointer ) bool {
if p .IsNil () {
return false
}
if nullable {
return !p .Apply (fieldOffset ).Elem ().IsNil ()
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
switch rv .Kind () {
case reflect .Bool :
return rv .Bool ()
case reflect .Int32 , reflect .Int64 :
return rv .Int () != 0
case reflect .Uint32 , reflect .Uint64 :
return rv .Uint () != 0
case reflect .Float32 , reflect .Float64 :
return rv .Float () != 0 || math .Signbit (rv .Float ())
case reflect .String , reflect .Slice :
return rv .Len () > 0
default :
panic (fmt .Sprintf ("field %v has invalid type: %v" , fd .FullName (), rv .Type ()))
}
},
clear : func (p pointer ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
rv .Set (reflect .Zero (rv .Type ()))
},
get : getter ,
set : func (p pointer , v protoreflect .Value ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if nullable && rv .Kind () == reflect .Ptr {
if rv .IsNil () {
rv .Set (reflect .New (ft ))
}
rv = rv .Elem ()
}
rv .Set (conv .GoValueOf (v ))
if isBytes && rv .Len () == 0 {
if nullable {
rv .Set (emptyBytes )
} else {
rv .Set (nilBytes )
}
}
},
newField : func () protoreflect .Value {
return conv .New ()
},
}
}
func fieldInfoForMessage(fd protoreflect .FieldDescriptor , fs reflect .StructField , x exporter ) fieldInfo {
ft := fs .Type
conv := NewConverter (ft , fd )
fieldOffset := offsetOf (fs )
return fieldInfo {
fieldDesc : fd ,
has : func (p pointer ) bool {
if p .IsNil () {
return false
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if fs .Type .Kind () != reflect .Ptr {
return !rv .IsZero ()
}
return !rv .IsNil ()
},
clear : func (p pointer ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
rv .Set (reflect .Zero (rv .Type ()))
},
get : func (p pointer ) protoreflect .Value {
if p .IsNil () {
return conv .Zero ()
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
return conv .PBValueOf (rv )
},
set : func (p pointer , v protoreflect .Value ) {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
rv .Set (conv .GoValueOf (v ))
if fs .Type .Kind () == reflect .Ptr && rv .IsNil () {
panic (fmt .Sprintf ("field %v has invalid nil pointer" , fd .FullName ()))
}
},
mutable : func (p pointer ) protoreflect .Value {
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if fs .Type .Kind () == reflect .Ptr && rv .IsNil () {
rv .Set (conv .GoValueOf (conv .New ()))
}
return conv .PBValueOf (rv )
},
newMessage : func () protoreflect .Message {
return conv .New ().Message ()
},
newField : func () protoreflect .Value {
return conv .New ()
},
}
}
type oneofInfo struct {
oneofDesc protoreflect .OneofDescriptor
which func (pointer ) protoreflect .FieldNumber
}
func makeOneofInfo(od protoreflect .OneofDescriptor , si structInfo , x exporter ) *oneofInfo {
oi := &oneofInfo {oneofDesc : od }
if od .IsSynthetic () {
fs := si .fieldsByNumber [od .Fields ().Get (0 ).Number ()]
fieldOffset := offsetOf (fs )
oi .which = func (p pointer ) protoreflect .FieldNumber {
if p .IsNil () {
return 0
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if rv .IsNil () {
return 0
}
return od .Fields ().Get (0 ).Number ()
}
} else {
fs := si .oneofsByName [od .Name ()]
fieldOffset := offsetOf (fs )
oi .which = func (p pointer ) protoreflect .FieldNumber {
if p .IsNil () {
return 0
}
rv := p .Apply (fieldOffset ).AsValueOf (fs .Type ).Elem ()
if rv .IsNil () {
return 0
}
rv = rv .Elem ()
if rv .IsNil () {
return 0
}
return si .oneofWrappersByType [rv .Type ().Elem ()]
}
}
return oi
}
The pages are generated with Golds v0.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 .