github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/areflect/force.go (about)

     1  // Copyright (c) 2014 Arista Networks, Inc.
     2  // Use of this source code is governed by the Apache License 2.0
     3  // that can be found in the COPYING file.
     4  
     5  // Package areflect provides utilities to help with reflection.
     6  package areflect
     7  
     8  import (
     9  	"reflect"
    10  	"unsafe"
    11  )
    12  
    13  // ForceExport returns a new reflect.Value that is identical to the one passed
    14  // in argument except that it's considered as an exported symbol even if in
    15  // reality it isn't.
    16  //
    17  // The `reflect' package intentionally makes it impossible to access the value
    18  // of an unexported attribute.  The implementation of reflect.DeepEqual() cheats
    19  // as it bypasses this check.  Unfortunately, we can't use the same cheat, which
    20  // prevents us from re-implementing DeepEqual properly or implementing some other
    21  // reflection-based tools.  So this is our cheat on top of theirs.  It makes
    22  // the given reflect.Value appear as if it was exported.
    23  //
    24  // This function requires go1.6 or newer.
    25  func ForceExport(v reflect.Value) reflect.Value {
    26  	// constants from reflect/value.go
    27  	const flagStickyRO uintptr = 1 << 5
    28  	const flagEmbedRO uintptr = 1 << 6 // new in go1.6 (was flagIndir before)
    29  	const flagRO uintptr = flagStickyRO | flagEmbedRO
    30  	ptr := unsafe.Pointer(&v)
    31  	rv := (*struct {
    32  		typ  unsafe.Pointer // a *reflect.rtype (reflect.Type)
    33  		ptr  unsafe.Pointer // The value wrapped by this reflect.Value
    34  		flag uintptr
    35  	})(ptr)
    36  	rv.flag &= ^flagRO // Unset the flag so this value appears to be exported.
    37  	return v
    38  }