Blame vendor/github.com/davecgh/go-spew/spew/bypass.go

Packit Service 4d2de5
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
Packit Service 4d2de5
//
Packit Service 4d2de5
// Permission to use, copy, modify, and distribute this software for any
Packit Service 4d2de5
// purpose with or without fee is hereby granted, provided that the above
Packit Service 4d2de5
// copyright notice and this permission notice appear in all copies.
Packit Service 4d2de5
//
Packit Service 4d2de5
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Packit Service 4d2de5
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Packit Service 4d2de5
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Packit Service 4d2de5
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Packit Service 4d2de5
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Packit Service 4d2de5
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Packit Service 4d2de5
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Packit Service 4d2de5
Packit Service 4d2de5
// NOTE: Due to the following build constraints, this file will only be compiled
Packit Service 4d2de5
// when the code is not running on Google App Engine, compiled by GopherJS, and
Packit Service 4d2de5
// "-tags safe" is not added to the go build command line.  The "disableunsafe"
Packit Service 4d2de5
// tag is deprecated and thus should not be used.
Packit Service 4d2de5
// +build !js,!appengine,!safe,!disableunsafe
Packit Service 4d2de5
Packit Service 4d2de5
package spew
Packit Service 4d2de5
Packit Service 4d2de5
import (
Packit Service 4d2de5
	"reflect"
Packit Service 4d2de5
	"unsafe"
Packit Service 4d2de5
)
Packit Service 4d2de5
Packit Service 4d2de5
const (
Packit Service 4d2de5
	// UnsafeDisabled is a build-time constant which specifies whether or
Packit Service 4d2de5
	// not access to the unsafe package is available.
Packit Service 4d2de5
	UnsafeDisabled = false
Packit Service 4d2de5
Packit Service 4d2de5
	// ptrSize is the size of a pointer on the current arch.
Packit Service 4d2de5
	ptrSize = unsafe.Sizeof((*byte)(nil))
Packit Service 4d2de5
)
Packit Service 4d2de5
Packit Service 4d2de5
var (
Packit Service 4d2de5
	// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
Packit Service 4d2de5
	// internal reflect.Value fields.  These values are valid before golang
Packit Service 4d2de5
	// commit ecccf07e7f9d which changed the format.  The are also valid
Packit Service 4d2de5
	// after commit 82f48826c6c7 which changed the format again to mirror
Packit Service 4d2de5
	// the original format.  Code in the init function updates these offsets
Packit Service 4d2de5
	// as necessary.
Packit Service 4d2de5
	offsetPtr    = uintptr(ptrSize)
Packit Service 4d2de5
	offsetScalar = uintptr(0)
Packit Service 4d2de5
	offsetFlag   = uintptr(ptrSize * 2)
Packit Service 4d2de5
Packit Service 4d2de5
	// flagKindWidth and flagKindShift indicate various bits that the
Packit Service 4d2de5
	// reflect package uses internally to track kind information.
Packit Service 4d2de5
	//
Packit Service 4d2de5
	// flagRO indicates whether or not the value field of a reflect.Value is
Packit Service 4d2de5
	// read-only.
Packit Service 4d2de5
	//
Packit Service 4d2de5
	// flagIndir indicates whether the value field of a reflect.Value is
Packit Service 4d2de5
	// the actual data or a pointer to the data.
Packit Service 4d2de5
	//
Packit Service 4d2de5
	// These values are valid before golang commit 90a7c3c86944 which
Packit Service 4d2de5
	// changed their positions.  Code in the init function updates these
Packit Service 4d2de5
	// flags as necessary.
Packit Service 4d2de5
	flagKindWidth = uintptr(5)
Packit Service 4d2de5
	flagKindShift = uintptr(flagKindWidth - 1)
Packit Service 4d2de5
	flagRO        = uintptr(1 << 0)
Packit Service 4d2de5
	flagIndir     = uintptr(1 << 1)
Packit Service 4d2de5
)
Packit Service 4d2de5
Packit Service 4d2de5
func init() {
Packit Service 4d2de5
	// Older versions of reflect.Value stored small integers directly in the
Packit Service 4d2de5
	// ptr field (which is named val in the older versions).  Versions
Packit Service 4d2de5
	// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
Packit Service 4d2de5
	// scalar for this purpose which unfortunately came before the flag
Packit Service 4d2de5
	// field, so the offset of the flag field is different for those
Packit Service 4d2de5
	// versions.
Packit Service 4d2de5
	//
Packit Service 4d2de5
	// This code constructs a new reflect.Value from a known small integer
Packit Service 4d2de5
	// and checks if the size of the reflect.Value struct indicates it has
Packit Service 4d2de5
	// the scalar field. When it does, the offsets are updated accordingly.
Packit Service 4d2de5
	vv := reflect.ValueOf(0xf00)
Packit Service 4d2de5
	if unsafe.Sizeof(vv) == (ptrSize * 4) {
Packit Service 4d2de5
		offsetScalar = ptrSize * 2
Packit Service 4d2de5
		offsetFlag = ptrSize * 3
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	// Commit 90a7c3c86944 changed the flag positions such that the low
Packit Service 4d2de5
	// order bits are the kind.  This code extracts the kind from the flags
Packit Service 4d2de5
	// field and ensures it's the correct type.  When it's not, the flag
Packit Service 4d2de5
	// order has been changed to the newer format, so the flags are updated
Packit Service 4d2de5
	// accordingly.
Packit Service 4d2de5
	upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
Packit Service 4d2de5
	upfv := *(*uintptr)(upf)
Packit Service 4d2de5
	flagKindMask := uintptr((1<
Packit Service 4d2de5
	if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
Packit Service 4d2de5
		flagKindShift = 0
Packit Service 4d2de5
		flagRO = 1 << 5
Packit Service 4d2de5
		flagIndir = 1 << 6
Packit Service 4d2de5
Packit Service 4d2de5
		// Commit adf9b30e5594 modified the flags to separate the
Packit Service 4d2de5
		// flagRO flag into two bits which specifies whether or not the
Packit Service 4d2de5
		// field is embedded.  This causes flagIndir to move over a bit
Packit Service 4d2de5
		// and means that flagRO is the combination of either of the
Packit Service 4d2de5
		// original flagRO bit and the new bit.
Packit Service 4d2de5
		//
Packit Service 4d2de5
		// This code detects the change by extracting what used to be
Packit Service 4d2de5
		// the indirect bit to ensure it's set.  When it's not, the flag
Packit Service 4d2de5
		// order has been changed to the newer format, so the flags are
Packit Service 4d2de5
		// updated accordingly.
Packit Service 4d2de5
		if upfv&flagIndir == 0 {
Packit Service 4d2de5
			flagRO = 3 << 5
Packit Service 4d2de5
			flagIndir = 1 << 7
Packit Service 4d2de5
		}
Packit Service 4d2de5
	}
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
Packit Service 4d2de5
// the typical safety restrictions preventing access to unaddressable and
Packit Service 4d2de5
// unexported data.  It works by digging the raw pointer to the underlying
Packit Service 4d2de5
// value out of the protected value and generating a new unprotected (unsafe)
Packit Service 4d2de5
// reflect.Value to it.
Packit Service 4d2de5
//
Packit Service 4d2de5
// This allows us to check for implementations of the Stringer and error
Packit Service 4d2de5
// interfaces to be used for pretty printing ordinarily unaddressable and
Packit Service 4d2de5
// inaccessible values such as unexported struct fields.
Packit Service 4d2de5
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
Packit Service 4d2de5
	indirects := 1
Packit Service 4d2de5
	vt := v.Type()
Packit Service 4d2de5
	upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
Packit Service 4d2de5
	rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
Packit Service 4d2de5
	if rvf&flagIndir != 0 {
Packit Service 4d2de5
		vt = reflect.PtrTo(v.Type())
Packit Service 4d2de5
		indirects++
Packit Service 4d2de5
	} else if offsetScalar != 0 {
Packit Service 4d2de5
		// The value is in the scalar field when it's not one of the
Packit Service 4d2de5
		// reference types.
Packit Service 4d2de5
		switch vt.Kind() {
Packit Service 4d2de5
		case reflect.Uintptr:
Packit Service 4d2de5
		case reflect.Chan:
Packit Service 4d2de5
		case reflect.Func:
Packit Service 4d2de5
		case reflect.Map:
Packit Service 4d2de5
		case reflect.Ptr:
Packit Service 4d2de5
		case reflect.UnsafePointer:
Packit Service 4d2de5
		default:
Packit Service 4d2de5
			upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
Packit Service 4d2de5
				offsetScalar)
Packit Service 4d2de5
		}
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	pv := reflect.NewAt(vt, upv)
Packit Service 4d2de5
	rv = pv
Packit Service 4d2de5
	for i := 0; i < indirects; i++ {
Packit Service 4d2de5
		rv = rv.Elem()
Packit Service 4d2de5
	}
Packit Service 4d2de5
	return rv
Packit Service 4d2de5
}