...

Source file src/google.golang.org/protobuf/internal/impl/message_reflect_field.go

Documentation: google.golang.org/protobuf/internal/impl

     1  // Copyright 2018 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 impl
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"reflect"
    11  	"sync"
    12  
    13  	"google.golang.org/protobuf/internal/flags"
    14  	"google.golang.org/protobuf/reflect/protoreflect"
    15  	"google.golang.org/protobuf/reflect/protoregistry"
    16  )
    17  
    18  type fieldInfo struct {
    19  	fieldDesc protoreflect.FieldDescriptor
    20  
    21  	// These fields are used for protobuf reflection support.
    22  	has        func(pointer) bool
    23  	clear      func(pointer)
    24  	get        func(pointer) protoreflect.Value
    25  	set        func(pointer, protoreflect.Value)
    26  	mutable    func(pointer) protoreflect.Value
    27  	newMessage func() protoreflect.Message
    28  	newField   func() protoreflect.Value
    29  }
    30  
    31  func fieldInfoForMissing(fd protoreflect.FieldDescriptor) fieldInfo {
    32  	// This never occurs for generated message types.
    33  	// It implies that a hand-crafted type has missing Go fields
    34  	// for specific protobuf message fields.
    35  	return fieldInfo{
    36  		fieldDesc: fd,
    37  		has: func(p pointer) bool {
    38  			return false
    39  		},
    40  		clear: func(p pointer) {
    41  			panic("missing Go struct field for " + string(fd.FullName()))
    42  		},
    43  		get: func(p pointer) protoreflect.Value {
    44  			return fd.Default()
    45  		},
    46  		set: func(p pointer, v protoreflect.Value) {
    47  			panic("missing Go struct field for " + string(fd.FullName()))
    48  		},
    49  		mutable: func(p pointer) protoreflect.Value {
    50  			panic("missing Go struct field for " + string(fd.FullName()))
    51  		},
    52  		newMessage: func() protoreflect.Message {
    53  			panic("missing Go struct field for " + string(fd.FullName()))
    54  		},
    55  		newField: func() protoreflect.Value {
    56  			if v := fd.Default(); v.IsValid() {
    57  				return v
    58  			}
    59  			panic("missing Go struct field for " + string(fd.FullName()))
    60  		},
    61  	}
    62  }
    63  
    64  func fieldInfoForOneof(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter, ot reflect.Type) fieldInfo {
    65  	ft := fs.Type
    66  	if ft.Kind() != reflect.Interface {
    67  		panic(fmt.Sprintf("field %v has invalid type: got %v, want interface kind", fd.FullName(), ft))
    68  	}
    69  	if ot.Kind() != reflect.Struct {
    70  		panic(fmt.Sprintf("field %v has invalid type: got %v, want struct kind", fd.FullName(), ot))
    71  	}
    72  	if !reflect.PtrTo(ot).Implements(ft) {
    73  		panic(fmt.Sprintf("field %v has invalid type: %v does not implement %v", fd.FullName(), ot, ft))
    74  	}
    75  	conv := NewConverter(ot.Field(0).Type, fd)
    76  	isMessage := fd.Message() != nil
    77  
    78  	// TODO: Implement unsafe fast path?
    79  	fieldOffset := offsetOf(fs, x)
    80  	return fieldInfo{
    81  		// NOTE: The logic below intentionally assumes that oneof fields are
    82  		// well-formatted. That is, the oneof interface never contains a
    83  		// typed nil pointer to one of the wrapper structs.
    84  
    85  		fieldDesc: fd,
    86  		has: func(p pointer) bool {
    87  			if p.IsNil() {
    88  				return false
    89  			}
    90  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
    91  			if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
    92  				return false
    93  			}
    94  			return true
    95  		},
    96  		clear: func(p pointer) {
    97  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
    98  			if rv.IsNil() || rv.Elem().Type().Elem() != ot {
    99  				// NOTE: We intentionally don't check for rv.Elem().IsNil()
   100  				// so that (*OneofWrapperType)(nil) gets cleared to nil.
   101  				return
   102  			}
   103  			rv.Set(reflect.Zero(rv.Type()))
   104  		},
   105  		get: func(p pointer) protoreflect.Value {
   106  			if p.IsNil() {
   107  				return conv.Zero()
   108  			}
   109  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   110  			if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
   111  				return conv.Zero()
   112  			}
   113  			rv = rv.Elem().Elem().Field(0)
   114  			return conv.PBValueOf(rv)
   115  		},
   116  		set: func(p pointer, v protoreflect.Value) {
   117  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   118  			if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
   119  				rv.Set(reflect.New(ot))
   120  			}
   121  			rv = rv.Elem().Elem().Field(0)
   122  			rv.Set(conv.GoValueOf(v))
   123  		},
   124  		mutable: func(p pointer) protoreflect.Value {
   125  			if !isMessage {
   126  				panic(fmt.Sprintf("field %v with invalid Mutable call on field with non-composite type", fd.FullName()))
   127  			}
   128  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   129  			if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
   130  				rv.Set(reflect.New(ot))
   131  			}
   132  			rv = rv.Elem().Elem().Field(0)
   133  			if rv.Kind() == reflect.Ptr && rv.IsNil() {
   134  				rv.Set(conv.GoValueOf(protoreflect.ValueOfMessage(conv.New().Message())))
   135  			}
   136  			return conv.PBValueOf(rv)
   137  		},
   138  		newMessage: func() protoreflect.Message {
   139  			return conv.New().Message()
   140  		},
   141  		newField: func() protoreflect.Value {
   142  			return conv.New()
   143  		},
   144  	}
   145  }
   146  
   147  func fieldInfoForMap(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
   148  	ft := fs.Type
   149  	if ft.Kind() != reflect.Map {
   150  		panic(fmt.Sprintf("field %v has invalid type: got %v, want map kind", fd.FullName(), ft))
   151  	}
   152  	conv := NewConverter(ft, fd)
   153  
   154  	// TODO: Implement unsafe fast path?
   155  	fieldOffset := offsetOf(fs, x)
   156  	return fieldInfo{
   157  		fieldDesc: fd,
   158  		has: func(p pointer) bool {
   159  			if p.IsNil() {
   160  				return false
   161  			}
   162  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   163  			return rv.Len() > 0
   164  		},
   165  		clear: func(p pointer) {
   166  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   167  			rv.Set(reflect.Zero(rv.Type()))
   168  		},
   169  		get: func(p pointer) protoreflect.Value {
   170  			if p.IsNil() {
   171  				return conv.Zero()
   172  			}
   173  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   174  			if rv.Len() == 0 {
   175  				return conv.Zero()
   176  			}
   177  			return conv.PBValueOf(rv)
   178  		},
   179  		set: func(p pointer, v protoreflect.Value) {
   180  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   181  			pv := conv.GoValueOf(v)
   182  			if pv.IsNil() {
   183  				panic(fmt.Sprintf("map field %v cannot be set with read-only value", fd.FullName()))
   184  			}
   185  			rv.Set(pv)
   186  		},
   187  		mutable: func(p pointer) protoreflect.Value {
   188  			v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   189  			if v.IsNil() {
   190  				v.Set(reflect.MakeMap(fs.Type))
   191  			}
   192  			return conv.PBValueOf(v)
   193  		},
   194  		newField: func() protoreflect.Value {
   195  			return conv.New()
   196  		},
   197  	}
   198  }
   199  
   200  func fieldInfoForList(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
   201  	ft := fs.Type
   202  	if ft.Kind() != reflect.Slice {
   203  		panic(fmt.Sprintf("field %v has invalid type: got %v, want slice kind", fd.FullName(), ft))
   204  	}
   205  	conv := NewConverter(reflect.PtrTo(ft), fd)
   206  
   207  	// TODO: Implement unsafe fast path?
   208  	fieldOffset := offsetOf(fs, x)
   209  	return fieldInfo{
   210  		fieldDesc: fd,
   211  		has: func(p pointer) bool {
   212  			if p.IsNil() {
   213  				return false
   214  			}
   215  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   216  			return rv.Len() > 0
   217  		},
   218  		clear: func(p pointer) {
   219  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   220  			rv.Set(reflect.Zero(rv.Type()))
   221  		},
   222  		get: func(p pointer) protoreflect.Value {
   223  			if p.IsNil() {
   224  				return conv.Zero()
   225  			}
   226  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
   227  			if rv.Elem().Len() == 0 {
   228  				return conv.Zero()
   229  			}
   230  			return conv.PBValueOf(rv)
   231  		},
   232  		set: func(p pointer, v protoreflect.Value) {
   233  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   234  			pv := conv.GoValueOf(v)
   235  			if pv.IsNil() {
   236  				panic(fmt.Sprintf("list field %v cannot be set with read-only value", fd.FullName()))
   237  			}
   238  			rv.Set(pv.Elem())
   239  		},
   240  		mutable: func(p pointer) protoreflect.Value {
   241  			v := p.Apply(fieldOffset).AsValueOf(fs.Type)
   242  			return conv.PBValueOf(v)
   243  		},
   244  		newField: func() protoreflect.Value {
   245  			return conv.New()
   246  		},
   247  	}
   248  }
   249  
   250  var (
   251  	nilBytes   = reflect.ValueOf([]byte(nil))
   252  	emptyBytes = reflect.ValueOf([]byte{})
   253  )
   254  
   255  func fieldInfoForScalar(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
   256  	ft := fs.Type
   257  	nullable := fd.HasPresence()
   258  	isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8
   259  	if nullable {
   260  		if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
   261  			// This never occurs for generated message types.
   262  			// Despite the protobuf type system specifying presence,
   263  			// the Go field type cannot represent it.
   264  			nullable = false
   265  		}
   266  		if ft.Kind() == reflect.Ptr {
   267  			ft = ft.Elem()
   268  		}
   269  	}
   270  	conv := NewConverter(ft, fd)
   271  
   272  	// TODO: Implement unsafe fast path?
   273  	fieldOffset := offsetOf(fs, x)
   274  	return fieldInfo{
   275  		fieldDesc: fd,
   276  		has: func(p pointer) bool {
   277  			if p.IsNil() {
   278  				return false
   279  			}
   280  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   281  			if nullable {
   282  				return !rv.IsNil()
   283  			}
   284  			switch rv.Kind() {
   285  			case reflect.Bool:
   286  				return rv.Bool()
   287  			case reflect.Int32, reflect.Int64:
   288  				return rv.Int() != 0
   289  			case reflect.Uint32, reflect.Uint64:
   290  				return rv.Uint() != 0
   291  			case reflect.Float32, reflect.Float64:
   292  				return rv.Float() != 0 || math.Signbit(rv.Float())
   293  			case reflect.String, reflect.Slice:
   294  				return rv.Len() > 0
   295  			default:
   296  				panic(fmt.Sprintf("field %v has invalid type: %v", fd.FullName(), rv.Type())) // should never happen
   297  			}
   298  		},
   299  		clear: func(p pointer) {
   300  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   301  			rv.Set(reflect.Zero(rv.Type()))
   302  		},
   303  		get: func(p pointer) protoreflect.Value {
   304  			if p.IsNil() {
   305  				return conv.Zero()
   306  			}
   307  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   308  			if nullable {
   309  				if rv.IsNil() {
   310  					return conv.Zero()
   311  				}
   312  				if rv.Kind() == reflect.Ptr {
   313  					rv = rv.Elem()
   314  				}
   315  			}
   316  			return conv.PBValueOf(rv)
   317  		},
   318  		set: func(p pointer, v protoreflect.Value) {
   319  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   320  			if nullable && rv.Kind() == reflect.Ptr {
   321  				if rv.IsNil() {
   322  					rv.Set(reflect.New(ft))
   323  				}
   324  				rv = rv.Elem()
   325  			}
   326  			rv.Set(conv.GoValueOf(v))
   327  			if isBytes && rv.Len() == 0 {
   328  				if nullable {
   329  					rv.Set(emptyBytes) // preserve presence
   330  				} else {
   331  					rv.Set(nilBytes) // do not preserve presence
   332  				}
   333  			}
   334  		},
   335  		newField: func() protoreflect.Value {
   336  			return conv.New()
   337  		},
   338  	}
   339  }
   340  
   341  func fieldInfoForWeakMessage(fd protoreflect.FieldDescriptor, weakOffset offset) fieldInfo {
   342  	if !flags.ProtoLegacy {
   343  		panic("no support for proto1 weak fields")
   344  	}
   345  
   346  	var once sync.Once
   347  	var messageType protoreflect.MessageType
   348  	lazyInit := func() {
   349  		once.Do(func() {
   350  			messageName := fd.Message().FullName()
   351  			messageType, _ = protoregistry.GlobalTypes.FindMessageByName(messageName)
   352  			if messageType == nil {
   353  				panic(fmt.Sprintf("weak message %v for field %v is not linked in", messageName, fd.FullName()))
   354  			}
   355  		})
   356  	}
   357  
   358  	num := fd.Number()
   359  	return fieldInfo{
   360  		fieldDesc: fd,
   361  		has: func(p pointer) bool {
   362  			if p.IsNil() {
   363  				return false
   364  			}
   365  			_, ok := p.Apply(weakOffset).WeakFields().get(num)
   366  			return ok
   367  		},
   368  		clear: func(p pointer) {
   369  			p.Apply(weakOffset).WeakFields().clear(num)
   370  		},
   371  		get: func(p pointer) protoreflect.Value {
   372  			lazyInit()
   373  			if p.IsNil() {
   374  				return protoreflect.ValueOfMessage(messageType.Zero())
   375  			}
   376  			m, ok := p.Apply(weakOffset).WeakFields().get(num)
   377  			if !ok {
   378  				return protoreflect.ValueOfMessage(messageType.Zero())
   379  			}
   380  			return protoreflect.ValueOfMessage(m.ProtoReflect())
   381  		},
   382  		set: func(p pointer, v protoreflect.Value) {
   383  			lazyInit()
   384  			m := v.Message()
   385  			if m.Descriptor() != messageType.Descriptor() {
   386  				if got, want := m.Descriptor().FullName(), messageType.Descriptor().FullName(); got != want {
   387  					panic(fmt.Sprintf("field %v has mismatching message descriptor: got %v, want %v", fd.FullName(), got, want))
   388  				}
   389  				panic(fmt.Sprintf("field %v has mismatching message descriptor: %v", fd.FullName(), m.Descriptor().FullName()))
   390  			}
   391  			p.Apply(weakOffset).WeakFields().set(num, m.Interface())
   392  		},
   393  		mutable: func(p pointer) protoreflect.Value {
   394  			lazyInit()
   395  			fs := p.Apply(weakOffset).WeakFields()
   396  			m, ok := fs.get(num)
   397  			if !ok {
   398  				m = messageType.New().Interface()
   399  				fs.set(num, m)
   400  			}
   401  			return protoreflect.ValueOfMessage(m.ProtoReflect())
   402  		},
   403  		newMessage: func() protoreflect.Message {
   404  			lazyInit()
   405  			return messageType.New()
   406  		},
   407  		newField: func() protoreflect.Value {
   408  			lazyInit()
   409  			return protoreflect.ValueOfMessage(messageType.New())
   410  		},
   411  	}
   412  }
   413  
   414  func fieldInfoForMessage(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
   415  	ft := fs.Type
   416  	conv := NewConverter(ft, fd)
   417  
   418  	// TODO: Implement unsafe fast path?
   419  	fieldOffset := offsetOf(fs, x)
   420  	return fieldInfo{
   421  		fieldDesc: fd,
   422  		has: func(p pointer) bool {
   423  			if p.IsNil() {
   424  				return false
   425  			}
   426  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   427  			if fs.Type.Kind() != reflect.Ptr {
   428  				return !isZero(rv)
   429  			}
   430  			return !rv.IsNil()
   431  		},
   432  		clear: func(p pointer) {
   433  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   434  			rv.Set(reflect.Zero(rv.Type()))
   435  		},
   436  		get: func(p pointer) protoreflect.Value {
   437  			if p.IsNil() {
   438  				return conv.Zero()
   439  			}
   440  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   441  			return conv.PBValueOf(rv)
   442  		},
   443  		set: func(p pointer, v protoreflect.Value) {
   444  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   445  			rv.Set(conv.GoValueOf(v))
   446  			if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
   447  				panic(fmt.Sprintf("field %v has invalid nil pointer", fd.FullName()))
   448  			}
   449  		},
   450  		mutable: func(p pointer) protoreflect.Value {
   451  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   452  			if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
   453  				rv.Set(conv.GoValueOf(conv.New()))
   454  			}
   455  			return conv.PBValueOf(rv)
   456  		},
   457  		newMessage: func() protoreflect.Message {
   458  			return conv.New().Message()
   459  		},
   460  		newField: func() protoreflect.Value {
   461  			return conv.New()
   462  		},
   463  	}
   464  }
   465  
   466  type oneofInfo struct {
   467  	oneofDesc protoreflect.OneofDescriptor
   468  	which     func(pointer) protoreflect.FieldNumber
   469  }
   470  
   471  func makeOneofInfo(od protoreflect.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
   472  	oi := &oneofInfo{oneofDesc: od}
   473  	if od.IsSynthetic() {
   474  		fs := si.fieldsByNumber[od.Fields().Get(0).Number()]
   475  		fieldOffset := offsetOf(fs, x)
   476  		oi.which = func(p pointer) protoreflect.FieldNumber {
   477  			if p.IsNil() {
   478  				return 0
   479  			}
   480  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   481  			if rv.IsNil() { // valid on either *T or []byte
   482  				return 0
   483  			}
   484  			return od.Fields().Get(0).Number()
   485  		}
   486  	} else {
   487  		fs := si.oneofsByName[od.Name()]
   488  		fieldOffset := offsetOf(fs, x)
   489  		oi.which = func(p pointer) protoreflect.FieldNumber {
   490  			if p.IsNil() {
   491  				return 0
   492  			}
   493  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
   494  			if rv.IsNil() {
   495  				return 0
   496  			}
   497  			rv = rv.Elem()
   498  			if rv.IsNil() {
   499  				return 0
   500  			}
   501  			return si.oneofWrappersByType[rv.Type().Elem()]
   502  		}
   503  	}
   504  	return oi
   505  }
   506  
   507  // isZero is identical to reflect.Value.IsZero.
   508  // TODO: Remove this when Go1.13 is the minimally supported Go version.
   509  func isZero(v reflect.Value) bool {
   510  	switch v.Kind() {
   511  	case reflect.Bool:
   512  		return !v.Bool()
   513  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   514  		return v.Int() == 0
   515  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   516  		return v.Uint() == 0
   517  	case reflect.Float32, reflect.Float64:
   518  		return math.Float64bits(v.Float()) == 0
   519  	case reflect.Complex64, reflect.Complex128:
   520  		c := v.Complex()
   521  		return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
   522  	case reflect.Array:
   523  		for i := 0; i < v.Len(); i++ {
   524  			if !isZero(v.Index(i)) {
   525  				return false
   526  			}
   527  		}
   528  		return true
   529  	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
   530  		return v.IsNil()
   531  	case reflect.String:
   532  		return v.Len() == 0
   533  	case reflect.Struct:
   534  		for i := 0; i < v.NumField(); i++ {
   535  			if !isZero(v.Field(i)) {
   536  				return false
   537  			}
   538  		}
   539  		return true
   540  	default:
   541  		panic(&reflect.ValueError{"reflect.Value.IsZero", v.Kind()})
   542  	}
   543  }
   544  

View as plain text