OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / davecgh / go-spew / spew / bypass.go
1 // Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
2 //
3 // Permission to use, copy, modify, and distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15 // NOTE: Due to the following build constraints, this file will only be compiled
16 // when the code is not running on Google App Engine, compiled by GopherJS, and
17 // "-tags safe" is not added to the go build command line.  The "disableunsafe"
18 // tag is deprecated and thus should not be used.
19 // +build !js,!appengine,!safe,!disableunsafe
20
21 package spew
22
23 import (
24         "reflect"
25         "unsafe"
26 )
27
28 const (
29         // UnsafeDisabled is a build-time constant which specifies whether or
30         // not access to the unsafe package is available.
31         UnsafeDisabled = false
32
33         // ptrSize is the size of a pointer on the current arch.
34         ptrSize = unsafe.Sizeof((*byte)(nil))
35 )
36
37 var (
38         // offsetPtr, offsetScalar, and offsetFlag are the offsets for the
39         // internal reflect.Value fields.  These values are valid before golang
40         // commit ecccf07e7f9d which changed the format.  The are also valid
41         // after commit 82f48826c6c7 which changed the format again to mirror
42         // the original format.  Code in the init function updates these offsets
43         // as necessary.
44         offsetPtr    = ptrSize
45         offsetScalar = uintptr(0)
46         offsetFlag   = ptrSize * 2
47
48         // flagKindWidth and flagKindShift indicate various bits that the
49         // reflect package uses internally to track kind information.
50         //
51         // flagRO indicates whether or not the value field of a reflect.Value is
52         // read-only.
53         //
54         // flagIndir indicates whether the value field of a reflect.Value is
55         // the actual data or a pointer to the data.
56         //
57         // These values are valid before golang commit 90a7c3c86944 which
58         // changed their positions.  Code in the init function updates these
59         // flags as necessary.
60         flagKindWidth = uintptr(5)
61         flagKindShift = flagKindWidth - 1
62         flagRO        = uintptr(1 << 0)
63         flagIndir     = uintptr(1 << 1)
64 )
65
66 func init() {
67         // Older versions of reflect.Value stored small integers directly in the
68         // ptr field (which is named val in the older versions).  Versions
69         // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
70         // scalar for this purpose which unfortunately came before the flag
71         // field, so the offset of the flag field is different for those
72         // versions.
73         //
74         // This code constructs a new reflect.Value from a known small integer
75         // and checks if the size of the reflect.Value struct indicates it has
76         // the scalar field. When it does, the offsets are updated accordingly.
77         vv := reflect.ValueOf(0xf00)
78         if unsafe.Sizeof(vv) == (ptrSize * 4) {
79                 offsetScalar = ptrSize * 2
80                 offsetFlag = ptrSize * 3
81         }
82
83         // Commit 90a7c3c86944 changed the flag positions such that the low
84         // order bits are the kind.  This code extracts the kind from the flags
85         // field and ensures it's the correct type.  When it's not, the flag
86         // order has been changed to the newer format, so the flags are updated
87         // accordingly.
88         upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
89         upfv := *(*uintptr)(upf)
90         flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
91         if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
92                 flagKindShift = 0
93                 flagRO = 1 << 5
94                 flagIndir = 1 << 6
95
96                 // Commit adf9b30e5594 modified the flags to separate the
97                 // flagRO flag into two bits which specifies whether or not the
98                 // field is embedded.  This causes flagIndir to move over a bit
99                 // and means that flagRO is the combination of either of the
100                 // original flagRO bit and the new bit.
101                 //
102                 // This code detects the change by extracting what used to be
103                 // the indirect bit to ensure it's set.  When it's not, the flag
104                 // order has been changed to the newer format, so the flags are
105                 // updated accordingly.
106                 if upfv&flagIndir == 0 {
107                         flagRO = 3 << 5
108                         flagIndir = 1 << 7
109                 }
110         }
111 }
112
113 // unsafeReflectValue converts the passed reflect.Value into a one that bypasses
114 // the typical safety restrictions preventing access to unaddressable and
115 // unexported data.  It works by digging the raw pointer to the underlying
116 // value out of the protected value and generating a new unprotected (unsafe)
117 // reflect.Value to it.
118 //
119 // This allows us to check for implementations of the Stringer and error
120 // interfaces to be used for pretty printing ordinarily unaddressable and
121 // inaccessible values such as unexported struct fields.
122 func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
123         indirects := 1
124         vt := v.Type()
125         upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
126         rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
127         if rvf&flagIndir != 0 {
128                 vt = reflect.PtrTo(v.Type())
129                 indirects++
130         } else if offsetScalar != 0 {
131                 // The value is in the scalar field when it's not one of the
132                 // reference types.
133                 switch vt.Kind() {
134                 case reflect.Uintptr:
135                 case reflect.Chan:
136                 case reflect.Func:
137                 case reflect.Map:
138                 case reflect.Ptr:
139                 case reflect.UnsafePointer:
140                 default:
141                         upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
142                                 offsetScalar)
143                 }
144         }
145
146         pv := reflect.NewAt(vt, upv)
147         rv = pv
148         for i := 0; i < indirects; i++ {
149                 rv = rv.Elem()
150         }
151         return rv
152 }