github.com/RevenueMonster/sqlike@v1.0.6/reflext/cache.go (about)

     1  package reflext
     2  
     3  import (
     4  	"reflect"
     5  	"runtime"
     6  	"sync"
     7  )
     8  
     9  // DefaultMapper :
    10  var DefaultMapper = NewMapperFunc("sqlike", nil)
    11  
    12  // StructMapper :
    13  type StructMapper interface {
    14  	CodecByType(t reflect.Type) Structer
    15  	FieldByName(v reflect.Value, name string) reflect.Value
    16  	FieldByIndexes(v reflect.Value, idxs []int) reflect.Value
    17  	FieldByIndexesReadOnly(v reflect.Value, idxs []int) reflect.Value
    18  	LookUpFieldByName(v reflect.Value, name string) (reflect.Value, bool)
    19  	TraversalsByName(t reflect.Type, names []string) (idxs [][]int)
    20  	TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int)) (idxs [][]int)
    21  }
    22  
    23  // MapFunc :
    24  type MapFunc func(StructFielder) (skip bool)
    25  
    26  // FormatFunc :
    27  type FormatFunc func(string) string
    28  
    29  // Mapper :
    30  type Mapper struct {
    31  	mutex   sync.Mutex
    32  	tag     string
    33  	cache   map[reflect.Type]*Struct
    34  	fmtFunc FormatFunc
    35  }
    36  
    37  var _ StructMapper = (*Mapper)(nil)
    38  
    39  // NewMapperFunc :
    40  func NewMapperFunc(tag string, fmtFunc FormatFunc) *Mapper {
    41  	return &Mapper{
    42  		cache:   make(map[reflect.Type]*Struct),
    43  		tag:     tag,
    44  		fmtFunc: fmtFunc,
    45  	}
    46  }
    47  
    48  // CodecByType :
    49  func (m *Mapper) CodecByType(t reflect.Type) Structer {
    50  	m.mutex.Lock()
    51  	defer m.mutex.Unlock()
    52  	mapping, ok := m.cache[t]
    53  	if !ok {
    54  		mapping = getCodec(t, m.tag, m.fmtFunc)
    55  		m.cache[t] = mapping
    56  	}
    57  	return mapping
    58  }
    59  
    60  // FieldByName : get reflect.Value from struct by field name
    61  func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value {
    62  	v = Indirect(v)
    63  	mustBe(v, reflect.Struct)
    64  
    65  	tm := m.CodecByType(v.Type())
    66  	fi, ok := tm.LookUpFieldByName(name)
    67  	if !ok {
    68  		panic("field not exists")
    69  	}
    70  	return FieldByIndexes(v, fi.Index())
    71  }
    72  
    73  // FieldByIndexes : get reflect.Value from struct by indexes. If the reflect.Value is nil, it will get initialized
    74  func (m *Mapper) FieldByIndexes(v reflect.Value, idxs []int) reflect.Value {
    75  	return FieldByIndexes(v, idxs)
    76  }
    77  
    78  // FieldByIndexesReadOnly : get reflect.Value from struct by indexes without initialized
    79  func (m *Mapper) FieldByIndexesReadOnly(v reflect.Value, idxs []int) reflect.Value {
    80  	return FieldByIndexesReadOnly(v, idxs)
    81  }
    82  
    83  // LookUpFieldByName : lookup reflect.Value from struct by field name
    84  func (m *Mapper) LookUpFieldByName(v reflect.Value, name string) (reflect.Value, bool) {
    85  	v = Indirect(v)
    86  	mustBe(v, reflect.Struct)
    87  
    88  	tm := m.CodecByType(v.Type())
    89  	fi, ok := tm.LookUpFieldByName(name)
    90  	if !ok {
    91  		return v, false
    92  	}
    93  	return FieldByIndexes(v, fi.Index()), true
    94  }
    95  
    96  // TraversalsByName :
    97  func (m *Mapper) TraversalsByName(t reflect.Type, names []string) (idxs [][]int) {
    98  	idxs = make([][]int, 0, len(names))
    99  	m.TraversalsByNameFunc(t, names, func(i int, idx []int) {
   100  		if idxs != nil {
   101  			idxs = append(idxs, idx)
   102  		} else {
   103  			idxs = append(idxs, nil)
   104  		}
   105  	})
   106  	return idxs
   107  }
   108  
   109  // TraversalsByNameFunc :
   110  func (m *Mapper) TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int)) (idxs [][]int) {
   111  	t = Deref(t)
   112  	mustBe(t, reflect.Struct)
   113  
   114  	idxs = make([][]int, 0, len(names))
   115  	cdc := m.CodecByType(t)
   116  	for i, name := range names {
   117  		sf, ok := cdc.LookUpFieldByName(name)
   118  		if ok {
   119  			fn(i, sf.Index())
   120  		} else {
   121  			fn(i, nil)
   122  		}
   123  	}
   124  	return idxs
   125  }
   126  
   127  // FieldByIndexes : get reflect.Value from struct by indexes. If the reflect.Value is nil, it will get initialized
   128  func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value {
   129  	for _, i := range indexes {
   130  		v = Indirect(v).Field(i)
   131  		v = Init(v)
   132  	}
   133  	return v
   134  }
   135  
   136  // FieldByIndexesReadOnly : get reflect.Value from struct by indexes without initialized
   137  func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value {
   138  	for _, i := range indexes {
   139  		if v.Kind() == reflect.Ptr && v.IsNil() {
   140  			v = reflect.Zero(v.Type())
   141  			break
   142  		}
   143  		v = Indirect(v).Field(i)
   144  	}
   145  	return v
   146  }
   147  
   148  type kinder interface {
   149  	Kind() reflect.Kind
   150  }
   151  
   152  func mustBe(v kinder, k reflect.Kind) {
   153  	if v.Kind() != k {
   154  		panic(&reflect.ValueError{Method: methodName(), Kind: k})
   155  	}
   156  }
   157  
   158  func methodName() string {
   159  	pc, _, _, _ := runtime.Caller(2)
   160  	f := runtime.FuncForPC(pc)
   161  	if f == nil {
   162  		return "unknown method"
   163  	}
   164  	return f.Name()
   165  }