github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/const/const_race.go (about)

     1  //go:build race
     2  
     3  package main
     4  
     5  import (
     6  	"reflect"
     7  	"runtime"
     8  )
     9  
    10  func Const[T any](v *T) struct{} {
    11  	go deepRaceRead(reflect.ValueOf(v))
    12  	return struct{}{}
    13  }
    14  
    15  func deepRaceRead(v reflect.Value) {
    16  	_ = runtime.KeepAlive
    17  	switch v.Type().Kind() {
    18  	default:
    19  		panic("unhandled type")
    20  	case reflect.Bool,
    21  		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
    22  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
    23  		reflect.Uintptr,
    24  		reflect.Float32, reflect.Float64,
    25  		reflect.Complex64, reflect.Complex128:
    26  		runtime.RaceRead(v.Addr().UnsafePointer())
    27  	case reflect.Ptr:
    28  		if v.IsNil() {
    29  			return
    30  		}
    31  		deepRaceRead(v.Elem())
    32  	case reflect.String:
    33  		runtime.RaceRead(v.UnsafePointer())
    34  	case reflect.Array, reflect.Slice:
    35  		// TODO: use runtime.RaceReadRange
    36  		for i := 0; i < v.Len(); i++ {
    37  			deepRaceRead(v.Index(i))
    38  		}
    39  	case reflect.Map:
    40  		if v.IsNil() {
    41  			return
    42  		}
    43  		iter := v.MapRange()
    44  		for iter.Next() {
    45  			deepRaceRead(iter.Value())
    46  		}
    47  	case reflect.Struct:
    48  		for i := 0; i < v.NumField(); i++ {
    49  			deepRaceRead(v.Field(i))
    50  		}
    51  	}
    52  }