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 reflectlite
import (
)
// 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.
// Access using the typ method to avoid escape of v.
typ_ *abi.Type
// 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 uintptr
const (
flagKindWidth = 5 // there are 27 kinds
flagKindMask flag = 1<<flagKindWidth - 1
flagStickyRO flag = 1 << 5
flagEmbedRO flag = 1 << 6
flagIndir flag = 1 << 7
flagAddr flag = 1 << 8
flagMethod flag = 1 << 9
flagMethodShift = 10
flagRO flag = flagStickyRO | flagEmbedRO
)
func ( flag) () Kind {
return Kind( & flagKindMask)
}
func ( flag) () flag {
if &flagRO != 0 {
return flagStickyRO
}
return 0
}
func ( Value) () *abi.Type {
// Types are either static (for compiler-created types) or
// heap-allocated but always reachable (for reflection-created
// types, held in the central map). So there is no need to
// escape types. noescape here help avoid unnecessary escape
// of v.
return (*abi.Type)(abi.NoEscape(unsafe.Pointer(.typ_)))
}
// pointer returns the underlying pointer represented by v.
// v.Kind() must be Pointer, Map, Chan, Func, or UnsafePointer
func ( Value) () unsafe.Pointer {
if .typ().Size() != goarch.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 packEface( Value) any {
:= .typ()
var any
:= (*abi.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.
:= .ptr
if .flag&flagAddr != 0 {
:= unsafe_New()
typedmemmove(, , )
=
}
.Data =
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.
.Data = *(*unsafe.Pointer)(.ptr)
default:
// Value is direct, and so is the interface.
.Data = .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.
.Type =
return
}
// unpackEface converts the empty interface i to a Value.
func unpackEface( any) Value {
:= (*abi.EmptyInterface)(unsafe.Pointer(&))
// NOTE: don't read e.word until we know whether it is really a pointer or not.
:= .Type
if == nil {
return Value{}
}
:= flag(.Kind())
if .IfaceIndir() {
|= flagIndir
}
return Value{, .Data, }
}
// 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 string
Kind 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 methodName() string {
, , , := runtime.Caller(2)
:= runtime.FuncForPC()
if == nil {
return "unknown method"
}
return .Name()
}
// 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(), abi.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 Pointer.
// It returns the zero Value if v is nil.
func ( Value) () Value {
:= .kind()
switch {
case abi.Interface:
var any
if .typ().NumMethod() == 0 {
= *(*any)(.ptr)
} else {
= (any)(*(*interface {
()
})(.ptr))
}
:= unpackEface()
if .flag != 0 {
.flag |= .flag.ro()
}
return
case abi.Pointer:
:= .ptr
if .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 valueInterface( Value) any {
if .flag == 0 {
panic(&ValueError{"reflectlite.Value.Interface", 0})
}
if .kind() == abi.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 *(*any)(.ptr)
}
return *(*interface {
()
})(.ptr)
}
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 abi.Chan, abi.Func, abi.Map, abi.Pointer, abi.UnsafePointer:
// if v.flag&flagMethod != 0 {
// return false
// }
:= .ptr
if .flag&flagIndir != 0 {
= *(*unsafe.Pointer)()
}
return == nil
case abi.Interface, abi.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:
//go:noescape
func chanlen(unsafe.Pointer) int
//go:noescape
func maplen(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 abi.Array:
:= (*arrayType)(unsafe.Pointer(.typ()))
return int(.Len)
case abi.Chan:
return chanlen(.pointer())
case abi.Map:
return maplen(.pointer())
case abi.Slice:
// Slice is bigger than a word; assume flagIndir.
return (*unsafeheader.Slice)(.ptr).Len
case abi.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", abi.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 leak
var unsafe.Pointer
if .kind() == abi.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 {
:= .flag
if == 0 {
panic(&ValueError{"reflectlite.Value.Type", abi.Invalid})
}
// Method values not supported.
return toRType(.typ())
}
/*
* constructors
*/
// implemented in package runtime
//go:noescape
func unsafe_New(*abi.Type) unsafe.Pointer
// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i. ValueOf(nil) returns the zero Value.
func ( any) Value {
if == nil {
return Value{}
}
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, *abi.Type, 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() == abi.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(abi.Interface)}
}
:= valueInterface()
if .NumMethod() == 0 {
*(*any)() =
} else {
ifaceE2I(, , )
}
return Value{, , flagIndir | flag(abi.Interface)}
}
// Failed.
panic( + ": value of type " + toRType(.typ()).String() + " is not assignable to type " + toRType().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 arrayAt( unsafe.Pointer, int, uintptr, string) unsafe.Pointer {
return add(, uintptr()*, "i < len")
}
func ifaceE2I( *abi.Type, any, unsafe.Pointer)
// typedmemmove copies a value of type t to dst from src.
//
//go:noescape
func typedmemmove( *abi.Type, , 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 escapes( any) {
if dummy.b {
dummy.x =
}
}
var dummy struct {
b bool
x any
}
The pages are generated with Golds v0.7.0-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |