message_opaque.go raw

   1  // Copyright 2024 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  	"strings"
  12  	"sync/atomic"
  13  
  14  	"google.golang.org/protobuf/internal/filedesc"
  15  	"google.golang.org/protobuf/reflect/protoreflect"
  16  )
  17  
  18  type opaqueStructInfo struct {
  19  	structInfo
  20  }
  21  
  22  // isOpaque determines whether a protobuf message type is on the Opaque API.  It
  23  // checks whether the type is a Go struct that protoc-gen-go would generate.
  24  //
  25  // This function only detects newly generated messages from the v2
  26  // implementation of protoc-gen-go. It is unable to classify generated messages
  27  // that are too old or those that are generated by a different generator
  28  // such as protoc-gen-gogo.
  29  func isOpaque(t reflect.Type) bool {
  30  	// The current detection mechanism is to simply check the first field
  31  	// for a struct tag with the "protogen" key.
  32  	if t.Kind() == reflect.Struct && t.NumField() > 0 {
  33  		pgt := t.Field(0).Tag.Get("protogen")
  34  		return strings.HasPrefix(pgt, "opaque.")
  35  	}
  36  	return false
  37  }
  38  
  39  func opaqueInitHook(mi *MessageInfo) bool {
  40  	mt := mi.GoReflectType.Elem()
  41  	si := opaqueStructInfo{
  42  		structInfo: mi.makeStructInfo(mt),
  43  	}
  44  
  45  	if !isOpaque(mt) {
  46  		return false
  47  	}
  48  
  49  	defer atomic.StoreUint32(&mi.initDone, 1)
  50  
  51  	mi.fields = map[protoreflect.FieldNumber]*fieldInfo{}
  52  	fds := mi.Desc.Fields()
  53  	for i := 0; i < fds.Len(); i++ {
  54  		fd := fds.Get(i)
  55  		fs := si.fieldsByNumber[fd.Number()]
  56  		var fi fieldInfo
  57  		usePresence, _ := filedesc.UsePresenceForField(fd)
  58  
  59  		switch {
  60  		case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
  61  			// Oneofs are no different for opaque.
  62  			fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
  63  		case fd.IsMap():
  64  			fi = mi.fieldInfoForMapOpaque(si, fd, fs)
  65  		case fd.IsList() && fd.Message() == nil && usePresence:
  66  			fi = mi.fieldInfoForScalarListOpaque(si, fd, fs)
  67  		case fd.IsList() && fd.Message() == nil:
  68  			// Proto3 lists without presence can use same access methods as open
  69  			fi = fieldInfoForList(fd, fs, mi.Exporter)
  70  		case fd.IsList() && usePresence:
  71  			fi = mi.fieldInfoForMessageListOpaque(si, fd, fs)
  72  		case fd.IsList():
  73  			// Proto3 opaque messages that does not need presence bitmap.
  74  			// Different representation than open struct, but same logic
  75  			fi = mi.fieldInfoForMessageListOpaqueNoPresence(si, fd, fs)
  76  		case fd.Message() != nil && usePresence:
  77  			fi = mi.fieldInfoForMessageOpaque(si, fd, fs)
  78  		case fd.Message() != nil:
  79  			// Proto3 messages without presence can use same access methods as open
  80  			fi = fieldInfoForMessage(fd, fs, mi.Exporter)
  81  		default:
  82  			fi = mi.fieldInfoForScalarOpaque(si, fd, fs)
  83  		}
  84  		mi.fields[fd.Number()] = &fi
  85  	}
  86  	mi.oneofs = map[protoreflect.Name]*oneofInfo{}
  87  	for i := 0; i < mi.Desc.Oneofs().Len(); i++ {
  88  		od := mi.Desc.Oneofs().Get(i)
  89  		mi.oneofs[od.Name()] = makeOneofInfoOpaque(mi, od, si.structInfo, mi.Exporter)
  90  	}
  91  
  92  	mi.denseFields = make([]*fieldInfo, fds.Len()*2)
  93  	for i := 0; i < fds.Len(); i++ {
  94  		if fd := fds.Get(i); int(fd.Number()) < len(mi.denseFields) {
  95  			mi.denseFields[fd.Number()] = mi.fields[fd.Number()]
  96  		}
  97  	}
  98  
  99  	for i := 0; i < fds.Len(); {
 100  		fd := fds.Get(i)
 101  		if od := fd.ContainingOneof(); od != nil && !fd.ContainingOneof().IsSynthetic() {
 102  			mi.rangeInfos = append(mi.rangeInfos, mi.oneofs[od.Name()])
 103  			i += od.Fields().Len()
 104  		} else {
 105  			mi.rangeInfos = append(mi.rangeInfos, mi.fields[fd.Number()])
 106  			i++
 107  		}
 108  	}
 109  
 110  	mi.makeExtensionFieldsFunc(mt, si.structInfo)
 111  	mi.makeUnknownFieldsFunc(mt, si.structInfo)
 112  	mi.makeOpaqueCoderMethods(mt, si)
 113  	mi.makeFieldTypes(si.structInfo)
 114  
 115  	return true
 116  }
 117  
 118  func makeOneofInfoOpaque(mi *MessageInfo, od protoreflect.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
 119  	oi := &oneofInfo{oneofDesc: od}
 120  	if od.IsSynthetic() {
 121  		fd := od.Fields().Get(0)
 122  		index, _ := presenceIndex(mi.Desc, fd)
 123  		oi.which = func(p pointer) protoreflect.FieldNumber {
 124  			if p.IsNil() {
 125  				return 0
 126  			}
 127  			if !mi.present(p, index) {
 128  				return 0
 129  			}
 130  			return od.Fields().Get(0).Number()
 131  		}
 132  		return oi
 133  	}
 134  	// Dispatch to non-opaque oneof implementation for non-synthetic oneofs.
 135  	return makeOneofInfo(od, si, x)
 136  }
 137  
 138  func (mi *MessageInfo) fieldInfoForMapOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
 139  	ft := fs.Type
 140  	if ft.Kind() != reflect.Map {
 141  		panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
 142  	}
 143  	fieldOffset := offsetOf(fs)
 144  	conv := NewConverter(ft, fd)
 145  	return fieldInfo{
 146  		fieldDesc: fd,
 147  		has: func(p pointer) bool {
 148  			if p.IsNil() {
 149  				return false
 150  			}
 151  			// Don't bother checking presence bits, since we need to
 152  			// look at the map length even if the presence bit is set.
 153  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 154  			return rv.Len() > 0
 155  		},
 156  		clear: func(p pointer) {
 157  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 158  			rv.Set(reflect.Zero(rv.Type()))
 159  		},
 160  		get: func(p pointer) protoreflect.Value {
 161  			if p.IsNil() {
 162  				return conv.Zero()
 163  			}
 164  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 165  			if rv.Len() == 0 {
 166  				return conv.Zero()
 167  			}
 168  			return conv.PBValueOf(rv)
 169  		},
 170  		set: func(p pointer, v protoreflect.Value) {
 171  			pv := conv.GoValueOf(v)
 172  			if pv.IsNil() {
 173  				panic(fmt.Sprintf("invalid value: setting map field to read-only value"))
 174  			}
 175  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 176  			rv.Set(pv)
 177  		},
 178  		mutable: func(p pointer) protoreflect.Value {
 179  			v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 180  			if v.IsNil() {
 181  				v.Set(reflect.MakeMap(fs.Type))
 182  			}
 183  			return conv.PBValueOf(v)
 184  		},
 185  		newField: func() protoreflect.Value {
 186  			return conv.New()
 187  		},
 188  	}
 189  }
 190  
 191  func (mi *MessageInfo) fieldInfoForScalarListOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
 192  	ft := fs.Type
 193  	if ft.Kind() != reflect.Slice {
 194  		panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
 195  	}
 196  	conv := NewConverter(reflect.PtrTo(ft), fd)
 197  	fieldOffset := offsetOf(fs)
 198  	index, _ := presenceIndex(mi.Desc, fd)
 199  	return fieldInfo{
 200  		fieldDesc: fd,
 201  		has: func(p pointer) bool {
 202  			if p.IsNil() {
 203  				return false
 204  			}
 205  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 206  			return rv.Len() > 0
 207  		},
 208  		clear: func(p pointer) {
 209  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 210  			rv.Set(reflect.Zero(rv.Type()))
 211  		},
 212  		get: func(p pointer) protoreflect.Value {
 213  			if p.IsNil() {
 214  				return conv.Zero()
 215  			}
 216  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
 217  			if rv.Elem().Len() == 0 {
 218  				return conv.Zero()
 219  			}
 220  			return conv.PBValueOf(rv)
 221  		},
 222  		set: func(p pointer, v protoreflect.Value) {
 223  			pv := conv.GoValueOf(v)
 224  			if pv.IsNil() {
 225  				panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
 226  			}
 227  			mi.setPresent(p, index)
 228  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 229  			rv.Set(pv.Elem())
 230  		},
 231  		mutable: func(p pointer) protoreflect.Value {
 232  			mi.setPresent(p, index)
 233  			return conv.PBValueOf(p.Apply(fieldOffset).AsValueOf(fs.Type))
 234  		},
 235  		newField: func() protoreflect.Value {
 236  			return conv.New()
 237  		},
 238  	}
 239  }
 240  
 241  func (mi *MessageInfo) fieldInfoForMessageListOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
 242  	ft := fs.Type
 243  	if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
 244  		panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
 245  	}
 246  	conv := NewConverter(ft, fd)
 247  	fieldOffset := offsetOf(fs)
 248  	index, _ := presenceIndex(mi.Desc, fd)
 249  	fieldNumber := fd.Number()
 250  	return fieldInfo{
 251  		fieldDesc: fd,
 252  		has: func(p pointer) bool {
 253  			if p.IsNil() {
 254  				return false
 255  			}
 256  			if !mi.present(p, index) {
 257  				return false
 258  			}
 259  			sp := p.Apply(fieldOffset).AtomicGetPointer()
 260  			if sp.IsNil() {
 261  				// Lazily unmarshal this field.
 262  				mi.lazyUnmarshal(p, fieldNumber)
 263  				sp = p.Apply(fieldOffset).AtomicGetPointer()
 264  			}
 265  			rv := sp.AsValueOf(fs.Type.Elem())
 266  			return rv.Elem().Len() > 0
 267  		},
 268  		clear: func(p pointer) {
 269  			fp := p.Apply(fieldOffset)
 270  			sp := fp.AtomicGetPointer()
 271  			if sp.IsNil() {
 272  				sp = fp.AtomicSetPointerIfNil(pointerOfValue(reflect.New(fs.Type.Elem())))
 273  				mi.setPresent(p, index)
 274  			}
 275  			rv := sp.AsValueOf(fs.Type.Elem())
 276  			rv.Elem().Set(reflect.Zero(rv.Type().Elem()))
 277  		},
 278  		get: func(p pointer) protoreflect.Value {
 279  			if p.IsNil() {
 280  				return conv.Zero()
 281  			}
 282  			if !mi.present(p, index) {
 283  				return conv.Zero()
 284  			}
 285  			sp := p.Apply(fieldOffset).AtomicGetPointer()
 286  			if sp.IsNil() {
 287  				// Lazily unmarshal this field.
 288  				mi.lazyUnmarshal(p, fieldNumber)
 289  				sp = p.Apply(fieldOffset).AtomicGetPointer()
 290  			}
 291  			rv := sp.AsValueOf(fs.Type.Elem())
 292  			if rv.Elem().Len() == 0 {
 293  				return conv.Zero()
 294  			}
 295  			return conv.PBValueOf(rv)
 296  		},
 297  		set: func(p pointer, v protoreflect.Value) {
 298  			fp := p.Apply(fieldOffset)
 299  			sp := fp.AtomicGetPointer()
 300  			if sp.IsNil() {
 301  				sp = fp.AtomicSetPointerIfNil(pointerOfValue(reflect.New(fs.Type.Elem())))
 302  				mi.setPresent(p, index)
 303  			}
 304  			rv := sp.AsValueOf(fs.Type.Elem())
 305  			val := conv.GoValueOf(v)
 306  			if val.IsNil() {
 307  				panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
 308  			} else {
 309  				rv.Elem().Set(val.Elem())
 310  			}
 311  		},
 312  		mutable: func(p pointer) protoreflect.Value {
 313  			fp := p.Apply(fieldOffset)
 314  			sp := fp.AtomicGetPointer()
 315  			if sp.IsNil() {
 316  				if mi.present(p, index) {
 317  					// Lazily unmarshal this field.
 318  					mi.lazyUnmarshal(p, fieldNumber)
 319  					sp = p.Apply(fieldOffset).AtomicGetPointer()
 320  				} else {
 321  					sp = fp.AtomicSetPointerIfNil(pointerOfValue(reflect.New(fs.Type.Elem())))
 322  					mi.setPresent(p, index)
 323  				}
 324  			}
 325  			rv := sp.AsValueOf(fs.Type.Elem())
 326  			return conv.PBValueOf(rv)
 327  		},
 328  		newField: func() protoreflect.Value {
 329  			return conv.New()
 330  		},
 331  	}
 332  }
 333  
 334  func (mi *MessageInfo) fieldInfoForMessageListOpaqueNoPresence(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
 335  	ft := fs.Type
 336  	if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
 337  		panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
 338  	}
 339  	conv := NewConverter(ft, fd)
 340  	fieldOffset := offsetOf(fs)
 341  	return fieldInfo{
 342  		fieldDesc: fd,
 343  		has: func(p pointer) bool {
 344  			if p.IsNil() {
 345  				return false
 346  			}
 347  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 348  			if rv.IsNil() {
 349  				return false
 350  			}
 351  			return rv.Elem().Len() > 0
 352  		},
 353  		clear: func(p pointer) {
 354  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 355  			if !rv.IsNil() {
 356  				rv.Elem().Set(reflect.Zero(rv.Type().Elem()))
 357  			}
 358  		},
 359  		get: func(p pointer) protoreflect.Value {
 360  			if p.IsNil() {
 361  				return conv.Zero()
 362  			}
 363  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 364  			if rv.IsNil() {
 365  				return conv.Zero()
 366  			}
 367  			if rv.Elem().Len() == 0 {
 368  				return conv.Zero()
 369  			}
 370  			return conv.PBValueOf(rv)
 371  		},
 372  		set: func(p pointer, v protoreflect.Value) {
 373  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 374  			if rv.IsNil() {
 375  				rv.Set(reflect.New(fs.Type.Elem()))
 376  			}
 377  			val := conv.GoValueOf(v)
 378  			if val.IsNil() {
 379  				panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
 380  			} else {
 381  				rv.Elem().Set(val.Elem())
 382  			}
 383  		},
 384  		mutable: func(p pointer) protoreflect.Value {
 385  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 386  			if rv.IsNil() {
 387  				rv.Set(reflect.New(fs.Type.Elem()))
 388  			}
 389  			return conv.PBValueOf(rv)
 390  		},
 391  		newField: func() protoreflect.Value {
 392  			return conv.New()
 393  		},
 394  	}
 395  }
 396  
 397  func (mi *MessageInfo) fieldInfoForScalarOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
 398  	ft := fs.Type
 399  	nullable := fd.HasPresence()
 400  	if oneof := fd.ContainingOneof(); oneof != nil && oneof.IsSynthetic() {
 401  		nullable = true
 402  	}
 403  	deref := false
 404  	if nullable && ft.Kind() == reflect.Ptr {
 405  		ft = ft.Elem()
 406  		deref = true
 407  	}
 408  	conv := NewConverter(ft, fd)
 409  	fieldOffset := offsetOf(fs)
 410  	index, _ := presenceIndex(mi.Desc, fd)
 411  	var getter func(p pointer) protoreflect.Value
 412  	if !nullable {
 413  		getter = getterForDirectScalar(fd, fs, conv, fieldOffset)
 414  	} else {
 415  		getter = getterForOpaqueNullableScalar(mi, index, fd, fs, conv, fieldOffset)
 416  	}
 417  	return fieldInfo{
 418  		fieldDesc: fd,
 419  		has: func(p pointer) bool {
 420  			if p.IsNil() {
 421  				return false
 422  			}
 423  			if nullable {
 424  				return mi.present(p, index)
 425  			}
 426  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 427  			switch rv.Kind() {
 428  			case reflect.Bool:
 429  				return rv.Bool()
 430  			case reflect.Int32, reflect.Int64:
 431  				return rv.Int() != 0
 432  			case reflect.Uint32, reflect.Uint64:
 433  				return rv.Uint() != 0
 434  			case reflect.Float32, reflect.Float64:
 435  				return rv.Float() != 0 || math.Signbit(rv.Float())
 436  			case reflect.String, reflect.Slice:
 437  				return rv.Len() > 0
 438  			default:
 439  				panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
 440  			}
 441  		},
 442  		clear: func(p pointer) {
 443  			if nullable {
 444  				mi.clearPresent(p, index)
 445  			}
 446  			// This is only valuable for bytes and strings, but we do it unconditionally.
 447  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 448  			rv.Set(reflect.Zero(rv.Type()))
 449  		},
 450  		get: getter,
 451  		// TODO: Implement unsafe fast path for set?
 452  		set: func(p pointer, v protoreflect.Value) {
 453  			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 454  			if deref {
 455  				if rv.IsNil() {
 456  					rv.Set(reflect.New(ft))
 457  				}
 458  				rv = rv.Elem()
 459  			}
 460  
 461  			rv.Set(conv.GoValueOf(v))
 462  			if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
 463  				rv.Set(emptyBytes)
 464  			}
 465  			if nullable {
 466  				mi.setPresent(p, index)
 467  			}
 468  		},
 469  		newField: func() protoreflect.Value {
 470  			return conv.New()
 471  		},
 472  	}
 473  }
 474  
 475  func (mi *MessageInfo) fieldInfoForMessageOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
 476  	ft := fs.Type
 477  	conv := NewConverter(ft, fd)
 478  	fieldOffset := offsetOf(fs)
 479  	index, _ := presenceIndex(mi.Desc, fd)
 480  	fieldNumber := fd.Number()
 481  	elemType := fs.Type.Elem()
 482  	return fieldInfo{
 483  		fieldDesc: fd,
 484  		has: func(p pointer) bool {
 485  			if p.IsNil() {
 486  				return false
 487  			}
 488  			return mi.present(p, index)
 489  		},
 490  		clear: func(p pointer) {
 491  			mi.clearPresent(p, index)
 492  			p.Apply(fieldOffset).AtomicSetNilPointer()
 493  		},
 494  		get: func(p pointer) protoreflect.Value {
 495  			if p.IsNil() || !mi.present(p, index) {
 496  				return conv.Zero()
 497  			}
 498  			fp := p.Apply(fieldOffset)
 499  			mp := fp.AtomicGetPointer()
 500  			if mp.IsNil() {
 501  				// Lazily unmarshal this field.
 502  				mi.lazyUnmarshal(p, fieldNumber)
 503  				mp = fp.AtomicGetPointer()
 504  			}
 505  			rv := mp.AsValueOf(elemType)
 506  			return conv.PBValueOf(rv)
 507  		},
 508  		set: func(p pointer, v protoreflect.Value) {
 509  			val := pointerOfValue(conv.GoValueOf(v))
 510  			if val.IsNil() {
 511  				panic("invalid nil pointer")
 512  			}
 513  			p.Apply(fieldOffset).AtomicSetPointer(val)
 514  			mi.setPresent(p, index)
 515  		},
 516  		mutable: func(p pointer) protoreflect.Value {
 517  			fp := p.Apply(fieldOffset)
 518  			mp := fp.AtomicGetPointer()
 519  			if mp.IsNil() {
 520  				if mi.present(p, index) {
 521  					// Lazily unmarshal this field.
 522  					mi.lazyUnmarshal(p, fieldNumber)
 523  					mp = fp.AtomicGetPointer()
 524  				} else {
 525  					mp = pointerOfValue(conv.GoValueOf(conv.New()))
 526  					fp.AtomicSetPointer(mp)
 527  					mi.setPresent(p, index)
 528  				}
 529  			}
 530  			return conv.PBValueOf(mp.AsValueOf(fs.Type.Elem()))
 531  		},
 532  		newMessage: func() protoreflect.Message {
 533  			return conv.New().Message()
 534  		},
 535  		newField: func() protoreflect.Value {
 536  			return conv.New()
 537  		},
 538  	}
 539  }
 540  
 541  // A presenceList wraps a List, updating presence bits as necessary when the
 542  // list contents change.
 543  type presenceList struct {
 544  	pvalueList
 545  	setPresence func(bool)
 546  }
 547  type pvalueList interface {
 548  	protoreflect.List
 549  	//Unwrapper
 550  }
 551  
 552  func (list presenceList) Append(v protoreflect.Value) {
 553  	list.pvalueList.Append(v)
 554  	list.setPresence(true)
 555  }
 556  func (list presenceList) Truncate(i int) {
 557  	list.pvalueList.Truncate(i)
 558  	list.setPresence(i > 0)
 559  }
 560  
 561  // presenceIndex returns the index to pass to presence functions.
 562  //
 563  // TODO: field.Desc.Index() would be simpler, and would give space to record the presence of oneof fields.
 564  func presenceIndex(md protoreflect.MessageDescriptor, fd protoreflect.FieldDescriptor) (uint32, presenceSize) {
 565  	found := false
 566  	var index, numIndices uint32
 567  	for i := 0; i < md.Fields().Len(); i++ {
 568  		f := md.Fields().Get(i)
 569  		if f == fd {
 570  			found = true
 571  			index = numIndices
 572  		}
 573  		if f.ContainingOneof() == nil || isLastOneofField(f) {
 574  			numIndices++
 575  		}
 576  	}
 577  	if !found {
 578  		panic(fmt.Sprintf("BUG: %v not in %v", fd.Name(), md.FullName()))
 579  	}
 580  	return index, presenceSize(numIndices)
 581  }
 582  
 583  func isLastOneofField(fd protoreflect.FieldDescriptor) bool {
 584  	fields := fd.ContainingOneof().Fields()
 585  	return fields.Get(fields.Len()-1) == fd
 586  }
 587  
 588  func (mi *MessageInfo) setPresent(p pointer, index uint32) {
 589  	p.Apply(mi.presenceOffset).PresenceInfo().SetPresent(index, mi.presenceSize)
 590  }
 591  
 592  func (mi *MessageInfo) clearPresent(p pointer, index uint32) {
 593  	p.Apply(mi.presenceOffset).PresenceInfo().ClearPresent(index)
 594  }
 595  
 596  func (mi *MessageInfo) present(p pointer, index uint32) bool {
 597  	return p.Apply(mi.presenceOffset).PresenceInfo().Present(index)
 598  }
 599