You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							145 lines
						
					
					
						
							4.6 KiB
						
					
					
				
			
		
		
	
	
							145 lines
						
					
					
						
							4.6 KiB
						
					
					
				| // Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
 | |
| //
 | |
| // Permission to use, copy, modify, and distribute this software for any
 | |
| // purpose with or without fee is hereby granted, provided that the above
 | |
| // copyright notice and this permission notice appear in all copies.
 | |
| //
 | |
| // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | |
| // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | |
| // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | |
| // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
| // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | |
| // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | |
| // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
| 
 | |
| // NOTE: Due to the following build constraints, this file will only be compiled
 | |
| // when the code is not running on Google App Engine, compiled by GopherJS, and
 | |
| // "-tags safe" is not added to the go build command line.  The "disableunsafe"
 | |
| // tag is deprecated and thus should not be used.
 | |
| // Go versions prior to 1.4 are disabled because they use a different layout
 | |
| // for interfaces which make the implementation of unsafeReflectValue more complex.
 | |
| // +build !js,!appengine,!safe,!disableunsafe,go1.4
 | |
| 
 | |
| package spew
 | |
| 
 | |
| import (
 | |
| 	"reflect"
 | |
| 	"unsafe"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// UnsafeDisabled is a build-time constant which specifies whether or
 | |
| 	// not access to the unsafe package is available.
 | |
| 	UnsafeDisabled = false
 | |
| 
 | |
| 	// ptrSize is the size of a pointer on the current arch.
 | |
| 	ptrSize = unsafe.Sizeof((*byte)(nil))
 | |
| )
 | |
| 
 | |
| type flag uintptr
 | |
| 
 | |
| var (
 | |
| 	// flagRO indicates whether the value field of a reflect.Value
 | |
| 	// is read-only.
 | |
| 	flagRO flag
 | |
| 
 | |
| 	// flagAddr indicates whether the address of the reflect.Value's
 | |
| 	// value may be taken.
 | |
| 	flagAddr flag
 | |
| )
 | |
| 
 | |
| // flagKindMask holds the bits that make up the kind
 | |
| // part of the flags field. In all the supported versions,
 | |
| // it is in the lower 5 bits.
 | |
| const flagKindMask = flag(0x1f)
 | |
| 
 | |
| // Different versions of Go have used different
 | |
| // bit layouts for the flags type. This table
 | |
| // records the known combinations.
 | |
| var okFlags = []struct {
 | |
| 	ro, addr flag
 | |
| }{{
 | |
| 	// From Go 1.4 to 1.5
 | |
| 	ro:   1 << 5,
 | |
| 	addr: 1 << 7,
 | |
| }, {
 | |
| 	// Up to Go tip.
 | |
| 	ro:   1<<5 | 1<<6,
 | |
| 	addr: 1 << 8,
 | |
| }}
 | |
| 
 | |
| var flagValOffset = func() uintptr {
 | |
| 	field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
 | |
| 	if !ok {
 | |
| 		panic("reflect.Value has no flag field")
 | |
| 	}
 | |
| 	return field.Offset
 | |
| }()
 | |
| 
 | |
| // flagField returns a pointer to the flag field of a reflect.Value.
 | |
| func flagField(v *reflect.Value) *flag {
 | |
| 	return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
 | |
| }
 | |
| 
 | |
| // unsafeReflectValue converts the passed reflect.Value into a one that bypasses
 | |
| // the typical safety restrictions preventing access to unaddressable and
 | |
| // unexported data.  It works by digging the raw pointer to the underlying
 | |
| // value out of the protected value and generating a new unprotected (unsafe)
 | |
| // reflect.Value to it.
 | |
| //
 | |
| // This allows us to check for implementations of the Stringer and error
 | |
| // interfaces to be used for pretty printing ordinarily unaddressable and
 | |
| // inaccessible values such as unexported struct fields.
 | |
| func unsafeReflectValue(v reflect.Value) reflect.Value {
 | |
| 	if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
 | |
| 		return v
 | |
| 	}
 | |
| 	flagFieldPtr := flagField(&v)
 | |
| 	*flagFieldPtr &^= flagRO
 | |
| 	*flagFieldPtr |= flagAddr
 | |
| 	return v
 | |
| }
 | |
| 
 | |
| // Sanity checks against future reflect package changes
 | |
| // to the type or semantics of the Value.flag field.
 | |
| func init() {
 | |
| 	field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
 | |
| 	if !ok {
 | |
| 		panic("reflect.Value has no flag field")
 | |
| 	}
 | |
| 	if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
 | |
| 		panic("reflect.Value flag field has changed kind")
 | |
| 	}
 | |
| 	type t0 int
 | |
| 	var t struct {
 | |
| 		A t0
 | |
| 		// t0 will have flagEmbedRO set.
 | |
| 		t0
 | |
| 		// a will have flagStickyRO set
 | |
| 		a t0
 | |
| 	}
 | |
| 	vA := reflect.ValueOf(t).FieldByName("A")
 | |
| 	va := reflect.ValueOf(t).FieldByName("a")
 | |
| 	vt0 := reflect.ValueOf(t).FieldByName("t0")
 | |
| 
 | |
| 	// Infer flagRO from the difference between the flags
 | |
| 	// for the (otherwise identical) fields in t.
 | |
| 	flagPublic := *flagField(&vA)
 | |
| 	flagWithRO := *flagField(&va) | *flagField(&vt0)
 | |
| 	flagRO = flagPublic ^ flagWithRO
 | |
| 
 | |
| 	// Infer flagAddr from the difference between a value
 | |
| 	// taken from a pointer and not.
 | |
| 	vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
 | |
| 	flagNoPtr := *flagField(&vA)
 | |
| 	flagPtr := *flagField(&vPtrA)
 | |
| 	flagAddr = flagNoPtr ^ flagPtr
 | |
| 
 | |
| 	// Check that the inferred flags tally with one of the known versions.
 | |
| 	for _, f := range okFlags {
 | |
| 		if flagRO == f.ro && flagAddr == f.addr {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	panic("reflect.Value read-only flag has changed semantics")
 | |
| }
 | |
| 
 |