github.com/searKing/golang/go@v1.2.117/reflect/value.go (about)

     1  // Copyright 2020 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package reflect
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"reflect"
    11  	"unsafe"
    12  
    13  	bytes_ "github.com/searKing/golang/go/bytes"
    14  	"github.com/searKing/golang/go/container/traversal"
    15  )
    16  
    17  const PtrSize = unsafe.Sizeof(uintptr(0)) // an ideal const, sizeof *void, as 4 << (^uintptr(0) >> 63)
    18  
    19  // IsEmptyValue reports whether v is empty value for its type.
    20  //
    21  // The zero value is:
    22  //
    23  // 0 for numeric types,
    24  // false for the boolean type, and
    25  // "" (the empty string) for strings, and
    26  // {} (the empty struct) for structs, and
    27  // untyped nil or typed nil or len == 0 for maps, slices, pointers, functions, interfaces, and channels.
    28  // Code borrowed from https://github.com/golang/go/blob/go1.22.0/src/encoding/json/encode.go#L306
    29  func IsEmptyValue(v reflect.Value) bool {
    30  	if !v.IsValid() {
    31  		return true
    32  	}
    33  	switch v.Kind() {
    34  	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
    35  		return v.Len() == 0
    36  	case reflect.Bool,
    37  		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
    38  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
    39  		reflect.Float32, reflect.Float64,
    40  		reflect.Interface, reflect.Pointer:
    41  		return v.IsZero()
    42  	default:
    43  		return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
    44  	}
    45  }
    46  
    47  // IsZeroValue reports whether v is zero value for its type.
    48  // Zero values are variables declared without an explicit initial value are given their zero value.
    49  //
    50  // The zero value is:
    51  //
    52  // 0 for numeric types,
    53  // false for the boolean type, and
    54  // "" (the empty string) for strings.
    55  // untyped nil or typed nil for maps, slices, pointers, functions, interfaces, and channels.
    56  func IsZeroValue(v reflect.Value) bool {
    57  	if !v.IsValid() {
    58  		return true
    59  	}
    60  
    61  	// Use v.IsZero instead since go1.13.
    62  	return v.IsZero()
    63  }
    64  
    65  // IsNilValue reports whether v is untyped nil or typed nil for its type.
    66  func IsNilValue(v reflect.Value) bool {
    67  	var zeroV reflect.Value
    68  	if v == zeroV {
    69  		return true
    70  	}
    71  	if !v.IsValid() {
    72  		// This should never happen, but will act as a safeguard for later,
    73  		// as a default value doesn't make sense here.
    74  		panic(&reflect.ValueError{Method: "reflect.Value.IsNilValue", Kind: v.Kind()})
    75  	}
    76  	switch v.Kind() {
    77  	case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.UnsafePointer,
    78  		reflect.Interface, reflect.Slice:
    79  		return v.IsNil()
    80  	default:
    81  		return false
    82  	}
    83  }
    84  
    85  func FollowValuePointer(v reflect.Value) reflect.Value {
    86  	v = reflect.Indirect(v)
    87  	if v.Kind() == reflect.Ptr {
    88  		return FollowValuePointer(v)
    89  	}
    90  	return v
    91  }
    92  
    93  // FieldValueInfo represents a single field found in a struct.
    94  type FieldValueInfo struct {
    95  	value       reflect.Value
    96  	structField reflect.StructField
    97  	index       []int
    98  }
    99  
   100  func (info FieldValueInfo) MiddleNodes() []any {
   101  
   102  	if !info.value.IsValid() {
   103  		return nil
   104  	}
   105  	if IsNilType(info.value.Type()) {
   106  		return nil
   107  	}
   108  	val := FollowValuePointer(info.value)
   109  	if val.Kind() != reflect.Struct {
   110  		return nil
   111  	}
   112  
   113  	var middles []any
   114  	// Scan typ for fields to include.
   115  	for i := 0; i < val.NumField(); i++ {
   116  		index := make([]int, len(info.index)+1)
   117  		copy(index, info.index)
   118  		index[len(info.index)] = i
   119  		middles = append(middles, FieldValueInfo{
   120  			value:       val.Field(i),
   121  			structField: val.Type().Field(i),
   122  			index:       index,
   123  		})
   124  	}
   125  	return middles
   126  }
   127  func (info FieldValueInfo) Depth() int {
   128  	return len(info.index)
   129  }
   130  
   131  func (info FieldValueInfo) Value() reflect.Value {
   132  	return info.value
   133  }
   134  
   135  func (info FieldValueInfo) StructField() (reflect.StructField, bool) {
   136  	if IsEmptyValue(reflect.ValueOf(info.structField)) {
   137  		return info.structField, false
   138  	}
   139  	return info.structField, true
   140  }
   141  
   142  func (info FieldValueInfo) Index() []int {
   143  	return info.index
   144  }
   145  
   146  func (info *FieldValueInfo) String() string {
   147  	//if IsNilValue(info.value) {
   148  	//	return fmt.Sprintf("%+v", nil)
   149  	//}
   150  	//info.value.String()
   151  	//return fmt.Sprintf("%+v %+v", info.value.Type().String(), info.value)
   152  
   153  	switch k := info.value.Kind(); k {
   154  	case reflect.Invalid:
   155  		return "<invalid value>"
   156  	case reflect.String:
   157  		return "[string: " + info.value.String() + "]"
   158  	}
   159  	// If you call String on a reflect.value of other type, it's better to
   160  	// print something than to panic. Useful in debugging.
   161  	return "[" + info.value.Type().String() + ":" + func() string {
   162  		if info.value.CanInterface() && info.value.Interface() == nil {
   163  			return "<nil value>"
   164  		}
   165  		return fmt.Sprintf(" %+v", info.value)
   166  	}() + "]"
   167  }
   168  
   169  type FieldValueInfoHandler interface {
   170  	Handler(info FieldValueInfo) (goon bool)
   171  }
   172  type FieldValueInfoHandlerFunc func(info FieldValueInfo) (goon bool)
   173  
   174  func (f FieldValueInfoHandlerFunc) Handler(info FieldValueInfo) (goon bool) {
   175  	return f(info)
   176  }
   177  
   178  func WalkValueDFS(val reflect.Value, handler FieldValueInfoHandler) {
   179  	traversal.DepthFirstSearchOrder(FieldValueInfo{
   180  		value: val,
   181  	}, traversal.HandlerFunc(func(node any, depth int) (goon bool) {
   182  		return handler.Handler(node.(FieldValueInfo))
   183  	}))
   184  }
   185  
   186  func WalkValueBFS(val reflect.Value, handler FieldValueInfoHandler) {
   187  	traversal.BreadthFirstSearchOrder(FieldValueInfo{
   188  		value: val,
   189  	}, traversal.HandlerFunc(func(node any, depth int) (goon bool) {
   190  		return handler.Handler(node.(FieldValueInfo))
   191  	}))
   192  }
   193  
   194  func DumpValueInfoDFS(v reflect.Value) string {
   195  	dumpInfo := &bytes.Buffer{}
   196  	first := true
   197  	WalkValueDFS(v, FieldValueInfoHandlerFunc(func(info FieldValueInfo) (goon bool) {
   198  		if first {
   199  			first = false
   200  			bytes_.NewIndent(dumpInfo, "", "\t", info.Depth())
   201  		} else {
   202  			bytes_.NewLine(dumpInfo, "", "\t", info.Depth())
   203  		}
   204  		dumpInfo.WriteString(fmt.Sprintf("%+v", info.String()))
   205  		return true
   206  	}))
   207  	return dumpInfo.String()
   208  }
   209  
   210  func DumpValueInfoBFS(v reflect.Value) string {
   211  	dumpInfo := &bytes.Buffer{}
   212  	first := true
   213  	WalkValueBFS(v, FieldValueInfoHandlerFunc(func(info FieldValueInfo) (goon bool) {
   214  		if first {
   215  			first = false
   216  			bytes_.NewIndent(dumpInfo, "", "\t", info.Depth())
   217  		} else {
   218  			bytes_.NewLine(dumpInfo, "", "\t", info.Depth())
   219  		}
   220  		dumpInfo.WriteString(fmt.Sprintf("%+v", info.String()))
   221  		return true
   222  	}))
   223  	return dumpInfo.String()
   224  }