github.com/searKing/golang/go@v1.2.117/reflect/type.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  
    12  	bytes_ "github.com/searKing/golang/go/bytes"
    13  	"github.com/searKing/golang/go/container/traversal"
    14  )
    15  
    16  // nil, unknown type
    17  func IsNilType(v reflect.Type) (result bool) {
    18  	return v == nil
    19  }
    20  func FollowTypePointer(v reflect.Type) reflect.Type {
    21  	if IsNilType(v) {
    22  		return v
    23  	}
    24  	if v.Kind() == reflect.Ptr {
    25  		return FollowTypePointer(v.Elem())
    26  	}
    27  	return v
    28  }
    29  
    30  // A field represents a single field found in a struct.
    31  type FieldTypeInfo struct {
    32  	structField reflect.StructField
    33  	index       []int
    34  }
    35  
    36  func (info FieldTypeInfo) MiddleNodes() []any {
    37  	typ := info.structField.Type
    38  	var middles []any
    39  	typ = FollowTypePointer(typ)
    40  	if IsNilType(typ) {
    41  		return nil
    42  	}
    43  	if typ.Kind() != reflect.Struct {
    44  		return nil
    45  	}
    46  	// Scan typ for fields to include.
    47  	for i := 0; i < typ.NumField(); i++ {
    48  		index := make([]int, len(info.index)+1)
    49  		copy(index, info.index)
    50  		index[len(info.index)] = i
    51  		sf := typ.Field(i)
    52  		middles = append(middles, FieldTypeInfo{
    53  			structField: sf,
    54  			index:       index,
    55  		})
    56  	}
    57  	return middles
    58  }
    59  
    60  func (info FieldTypeInfo) Depth() int {
    61  	return len(info.index)
    62  }
    63  
    64  func (info FieldTypeInfo) StructField() (reflect.StructField, bool) {
    65  	if IsEmptyValue(reflect.ValueOf(info.structField)) {
    66  		return info.structField, false
    67  	}
    68  	return info.structField, true
    69  }
    70  
    71  func (info FieldTypeInfo) Index() []int {
    72  	return info.index
    73  }
    74  
    75  func (info FieldTypeInfo) String() string {
    76  	if info.structField.Type == nil {
    77  		return fmt.Sprintf("%+v", nil)
    78  	}
    79  	return fmt.Sprintf("%+v", info.structField.Type.String())
    80  }
    81  
    82  type FieldTypeInfoHandler interface {
    83  	Handler(info FieldTypeInfo) (goon bool)
    84  }
    85  type FieldTypeInfoHandlerFunc func(info FieldTypeInfo) (goon bool)
    86  
    87  func (f FieldTypeInfoHandlerFunc) Handler(info FieldTypeInfo) (goon bool) {
    88  	return f(info)
    89  }
    90  
    91  // Breadth First Search
    92  func WalkTypeBFS(typ reflect.Type, handler FieldTypeInfoHandler) {
    93  	traversal.BreadthFirstSearchOrder(FieldTypeInfo{
    94  		structField: reflect.StructField{
    95  			Type: typ,
    96  		},
    97  	}, traversal.HandlerFunc(func(node any, depth int) (goon bool) {
    98  		return handler.Handler(node.(FieldTypeInfo))
    99  	}))
   100  }
   101  
   102  // Wid First Search
   103  func WalkTypeDFS(typ reflect.Type, handler FieldTypeInfoHandler) {
   104  	traversal.DepthFirstSearchOrder(FieldTypeInfo{
   105  		structField: reflect.StructField{
   106  			Type: typ,
   107  		},
   108  	}, traversal.HandlerFunc(func(node any, depth int) (goon bool) {
   109  		return handler.Handler(node.(FieldTypeInfo))
   110  	}))
   111  }
   112  
   113  func DumpTypeInfoDFS(t reflect.Type) string {
   114  	dumpInfo := &bytes.Buffer{}
   115  	first := true
   116  	WalkTypeDFS(t, FieldTypeInfoHandlerFunc(func(info FieldTypeInfo) (goon bool) {
   117  		if first {
   118  			first = false
   119  			bytes_.NewIndent(dumpInfo, "", "\t", info.Depth())
   120  		} else {
   121  			bytes_.NewLine(dumpInfo, "", "\t", info.Depth())
   122  		}
   123  		dumpInfo.WriteString(fmt.Sprintf("%+v", info.String()))
   124  		return true
   125  	}))
   126  	return dumpInfo.String()
   127  }
   128  
   129  func DumpTypeInfoBFS(t reflect.Type) string {
   130  	dumpInfo := &bytes.Buffer{}
   131  	first := true
   132  	WalkTypeBFS(t, FieldTypeInfoHandlerFunc(func(info FieldTypeInfo) (goon bool) {
   133  		if first {
   134  			first = false
   135  			bytes_.NewIndent(dumpInfo, "", "\t", info.Depth())
   136  		} else {
   137  			bytes_.NewLine(dumpInfo, "", "\t", info.Depth())
   138  		}
   139  		dumpInfo.WriteString(fmt.Sprintf("%+v", info.String()))
   140  		return true
   141  	}))
   142  	return dumpInfo.String()
   143  }