Source File
value.go
Belonging Package
internal/reflectlite
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package reflectliteimport ()const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const// Value is the reflection interface to a Go value.//// Not all methods apply to all kinds of values. Restrictions,// if any, are noted in the documentation for each method.// Use the Kind method to find out the kind of value before// calling kind-specific methods. Calling a method// inappropriate to the kind of type causes a run time panic.//// The zero Value represents no value.// Its IsValid method returns false, its Kind method returns Invalid,// its String method returns "<invalid Value>", and all other methods panic.// Most functions and methods never return an invalid value.// If one does, its documentation states the conditions explicitly.//// A Value can be used concurrently by multiple goroutines provided that// the underlying Go value can be used concurrently for the equivalent// direct operations.//// To compare two Values, compare the results of the Interface method.// Using == on two Values does not compare the underlying values// they represent.type Value struct {// typ holds the type of the value represented by a Value.typ *rtype// Pointer-valued data or, if flagIndir is set, pointer to data.// Valid when either flagIndir is set or typ.pointers() is true.ptr unsafe.Pointer// flag holds metadata about the value.// The lowest bits are flag bits:// - flagStickyRO: obtained via unexported not embedded field, so read-only// - flagEmbedRO: obtained via unexported embedded field, so read-only// - flagIndir: val holds a pointer to the data// - flagAddr: v.CanAddr is true (implies flagIndir)// Value cannot represent method values.// The next five bits give the Kind of the value.// This repeats typ.Kind() except for method values.// The remaining 23+ bits give a method number for method values.// If flag.kind() != Func, code can assume that flagMethod is unset.// If ifaceIndir(typ), code can assume that flagIndir is set.flag// A method value represents a curried method invocation// like r.Read for some receiver r. The typ+val+flag bits describe// the receiver r, but the flag's Kind bits say Func (methods are// functions), and the top bits of the flag give the method number// in r's type's method table.}type flag uintptrconst (flagKindWidth = 5 // there are 27 kindsflagKindMask flag = 1<<flagKindWidth - 1flagStickyRO flag = 1 << 5flagEmbedRO flag = 1 << 6flagIndir flag = 1 << 7flagAddr flag = 1 << 8flagMethod flag = 1 << 9flagMethodShift = 10flagRO flag = flagStickyRO | flagEmbedRO)func ( flag) () Kind {return Kind( & flagKindMask)}func ( flag) () flag {if &flagRO != 0 {return flagStickyRO}return 0}// pointer returns the underlying pointer represented by v.// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointerfunc ( Value) () unsafe.Pointer {if .typ.size != ptrSize || !.typ.pointers() {panic("can't call pointer on a non-pointer Value")}if .flag&flagIndir != 0 {return *(*unsafe.Pointer)(.ptr)}return .ptr}// packEface converts v to the empty interface.func ( Value) interface{} {:= .typvar interface{}:= (*emptyInterface)(unsafe.Pointer(&))// First, fill in the data portion of the interface.switch {case ifaceIndir():if .flag&flagIndir == 0 {panic("bad indir")}// Value is indirect, and so is the interface we're making.:= .ptrif .flag&flagAddr != 0 {// TODO: pass safe boolean from valueInterface so// we don't need to copy if safe==true?:= unsafe_New()typedmemmove(, , )=}.word =case .flag&flagIndir != 0:// Value is indirect, but interface is direct. We need// to load the data at v.ptr into the interface data word..word = *(*unsafe.Pointer)(.ptr)default:// Value is direct, and so is the interface..word = .ptr}// Now, fill in the type portion. We're very careful here not// to have any operation between the e.word and e.typ assignments// that would let the garbage collector observe the partially-built// interface value..typ =return}// unpackEface converts the empty interface i to a Value.func ( interface{}) Value {:= (*emptyInterface)(unsafe.Pointer(&))// NOTE: don't read e.word until we know whether it is really a pointer or not.:= .typif == nil {return Value{}}:= flag(.Kind())if ifaceIndir() {|= flagIndir}return Value{, .word, }}// A ValueError occurs when a Value method is invoked on// a Value that does not support it. Such cases are documented// in the description of each method.type ValueError struct {Method stringKind Kind}func ( *ValueError) () string {if .Kind == 0 {return "reflect: call of " + .Method + " on zero Value"}return "reflect: call of " + .Method + " on " + .Kind.String() + " Value"}// methodName returns the name of the calling method,// assumed to be two stack frames above.func () string {, , , := runtime.Caller(2):= runtime.FuncForPC()if == nil {return "unknown method"}return .Name()}// emptyInterface is the header for an interface{} value.type emptyInterface struct {typ *rtypeword unsafe.Pointer}// mustBeExported panics if f records that the value was obtained using// an unexported field.func ( flag) () {if == 0 {panic(&ValueError{methodName(), 0})}if &flagRO != 0 {panic("reflect: " + methodName() + " using value obtained using unexported field")}}// mustBeAssignable panics if f records that the value is not assignable,// which is to say that either it was obtained using an unexported field// or it is not addressable.func ( flag) () {if == 0 {panic(&ValueError{methodName(), Invalid})}// Assignable if addressable and not read-only.if &flagRO != 0 {panic("reflect: " + methodName() + " using value obtained using unexported field")}if &flagAddr == 0 {panic("reflect: " + methodName() + " using unaddressable value")}}// CanSet reports whether the value of v can be changed.// A Value can be changed only if it is addressable and was not// obtained by the use of unexported struct fields.// If CanSet returns false, calling Set or any type-specific// setter (e.g., SetBool, SetInt) will panic.func ( Value) () bool {return .flag&(flagAddr|flagRO) == flagAddr}// Elem returns the value that the interface v contains// or that the pointer v points to.// It panics if v's Kind is not Interface or Ptr.// It returns the zero Value if v is nil.func ( Value) () Value {:= .kind()switch {case Interface:var interface{}if .typ.NumMethod() == 0 {= *(*interface{})(.ptr)} else {= (interface{})(*(*interface {()})(.ptr))}:= unpackEface()if .flag != 0 {.flag |= .flag.ro()}returncase Ptr::= .ptrif .flag&flagIndir != 0 {= *(*unsafe.Pointer)()}// The returned value's address is v's value.if == nil {return Value{}}:= (*ptrType)(unsafe.Pointer(.typ)):= .elem:= .flag&flagRO | flagIndir | flagAddr|= flag(.Kind())return Value{, , }}panic(&ValueError{"reflectlite.Value.Elem", .kind()})}func ( Value) interface{} {if .flag == 0 {panic(&ValueError{"reflectlite.Value.Interface", 0})}if .kind() == Interface {// Special case: return the element inside the interface.// Empty interface has one layout, all interfaces with// methods have a second layout.if .numMethod() == 0 {return *(*interface{})(.ptr)}return *(*interface {()})(.ptr)}// TODO: pass safe to packEface so we don't need to copy if safe==true?return packEface()}// IsNil reports whether its argument v is nil. The argument must be// a chan, func, interface, map, pointer, or slice value; if it is// not, IsNil panics. Note that IsNil is not always equivalent to a// regular comparison with nil in Go. For example, if v was created// by calling ValueOf with an uninitialized interface variable i,// i==nil will be true but v.IsNil will panic as v will be the zero// Value.func ( Value) () bool {:= .kind()switch {case Chan, Func, Map, Ptr, UnsafePointer:// if v.flag&flagMethod != 0 {// return false// }:= .ptrif .flag&flagIndir != 0 {= *(*unsafe.Pointer)()}return == nilcase Interface, Slice:// Both interface and slice are nil if first word is 0.// Both are always bigger than a word; assume flagIndir.return *(*unsafe.Pointer)(.ptr) == nil}panic(&ValueError{"reflectlite.Value.IsNil", .kind()})}// IsValid reports whether v represents a value.// It returns false if v is the zero Value.// If IsValid returns false, all other methods except String panic.// Most functions and methods never return an invalid Value.// If one does, its documentation states the conditions explicitly.func ( Value) () bool {return .flag != 0}// Kind returns v's Kind.// If v is the zero Value (IsValid returns false), Kind returns Invalid.func ( Value) () Kind {return .kind()}// implemented in runtime:func (unsafe.Pointer) intfunc (unsafe.Pointer) int// Len returns v's length.// It panics if v's Kind is not Array, Chan, Map, Slice, or String.func ( Value) () int {:= .kind()switch {case Array::= (*arrayType)(unsafe.Pointer(.typ))return int(.len)case Chan:return chanlen(.pointer())case Map:return maplen(.pointer())case Slice:// Slice is bigger than a word; assume flagIndir.return (*unsafeheader.Slice)(.ptr).Lencase String:// String is bigger than a word; assume flagIndir.return (*unsafeheader.String)(.ptr).Len}panic(&ValueError{"reflect.Value.Len", .kind()})}// NumMethod returns the number of exported methods in the value's method set.func ( Value) () int {if .typ == nil {panic(&ValueError{"reflectlite.Value.NumMethod", Invalid})}return .typ.NumMethod()}// Set assigns x to the value v.// It panics if CanSet returns false.// As in Go, x's value must be assignable to v's type.func ( Value) ( Value) {.mustBeAssignable().mustBeExported() // do not let unexported x leakvar unsafe.Pointerif .kind() == Interface {= .ptr}= .assignTo("reflectlite.Set", .typ, )if .flag&flagIndir != 0 {typedmemmove(.typ, .ptr, .ptr)} else {*(*unsafe.Pointer)(.ptr) = .ptr}}// Type returns v's type.func ( Value) () Type {:= .flagif == 0 {panic(&ValueError{"reflectlite.Value.Type", Invalid})}// Method values not supported.return .typ}/** constructors*/// implemented in package runtimefunc (*rtype) unsafe.Pointer// ValueOf returns a new Value initialized to the concrete value// stored in the interface i. ValueOf(nil) returns the zero Value.func ( interface{}) Value {if == nil {return Value{}}// TODO: Maybe allow contents of a Value to live on the stack.// For now we make the contents always escape to the heap. It// makes life easier in a few places (see chanrecv/mapassign// comment below).escapes()return unpackEface()}// assignTo returns a value v that can be assigned directly to typ.// It panics if v is not assignable to typ.// For a conversion to an interface type, target is a suggested scratch space to use.func ( Value) ( string, *rtype, unsafe.Pointer) Value {// if v.flag&flagMethod != 0 {// v = makeMethodValue(context, v)// }switch {case directlyAssignable(, .typ):// Overwrite type so that they match.// Same memory layout, so no harm done.:= .flag&(flagAddr|flagIndir) | .flag.ro()|= flag(.Kind())return Value{, .ptr, }case implements(, .typ):if == nil {= unsafe_New()}if .Kind() == Interface && .IsNil() {// A nil ReadWriter passed to nil Reader is OK,// but using ifaceE2I below will panic.// Avoid the panic by returning a nil dst (e.g., Reader) explicitly.return Value{, nil, flag(Interface)}}:= valueInterface()if .NumMethod() == 0 {*(*interface{})() =} else {ifaceE2I(, , )}return Value{, , flagIndir | flag(Interface)}}// Failed.panic( + ": value of type " + .typ.String() + " is not assignable to type " + .String())}// arrayAt returns the i-th element of p,// an array whose elements are eltSize bytes wide.// The array pointed at by p must have at least i+1 elements:// it is invalid (but impossible to check here) to pass i >= len,// because then the result will point outside the array.// whySafe must explain why i < len. (Passing "i < len" is fine;// the benefit is to surface this assumption at the call site.)func ( unsafe.Pointer, int, uintptr, string) unsafe.Pointer {return add(, uintptr()*, "i < len")}func ( *rtype, interface{}, unsafe.Pointer)// typedmemmove copies a value of type t to dst from src.//go:noescapefunc ( *rtype, , unsafe.Pointer)// Dummy annotation marking that the value x escapes,// for use in cases where the reflect code is so clever that// the compiler cannot follow.func ( interface{}) {if dummy.b {dummy.x =}}var dummy struct {b boolx interface{}}