github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/utils/reflector/reflector.go (about) 1 package reflector 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "sync" 8 "unicode" 9 10 "github.com/clubpay/ronykit/kit" 11 ) 12 13 var ( 14 ErrNotExported = fmt.Errorf("not exported") 15 ErrNoField = fmt.Errorf("field not exists") 16 ErrMessageIsNotStruct = fmt.Errorf("message is not a struct") 17 ) 18 19 type Reflector struct { 20 cacheMtx sync.RWMutex 21 cache map[reflect.Type]*Reflected 22 } 23 24 func New() *Reflector { 25 return &Reflector{ 26 cache: map[reflect.Type]*Reflected{}, 27 } 28 } 29 30 // Register registers the message then reflector will be much faster. You should call 31 // it concurrently. 32 func Register(m kit.Message, tags ...string) { 33 if m == nil { 34 return 35 } 36 37 mVal, err := getValue(m) 38 if err != nil { 39 return 40 } 41 mType := mVal.Type() 42 registered[mType] = destruct(mType, tags...) 43 } 44 45 func getValue(m kit.Message) (reflect.Value, error) { 46 mVal := reflect.Indirect(reflect.ValueOf(m)) 47 if mVal.Kind() != reflect.Struct { 48 return reflect.Value{}, ErrMessageIsNotStruct 49 } 50 51 return mVal, nil 52 } 53 54 func destruct(mType reflect.Type, tags ...string) *Reflected { 55 r := &Reflected{ 56 obj: Fields{}, 57 byTag: map[string]Fields{}, 58 typ: mType, 59 } 60 61 for i := 0; i < mType.NumField(); i++ { 62 ft := mType.Field(i) 63 if ft.PkgPath != "" { 64 continue 65 } 66 fi := FieldInfo{ 67 idx: i, 68 f: ft, 69 name: ft.Name, 70 offset: ft.Offset, 71 typ: ft.Type, 72 } 73 74 switch ft.Type.Kind() { 75 case reflect.Map, reflect.Slice, reflect.Ptr, 76 reflect.Interface, reflect.Array, reflect.Chan, 77 reflect.Complex64, reflect.Complex128, reflect.UnsafePointer: 78 default: 79 fi.unsafe = true 80 } 81 82 r.obj[fi.name] = fi 83 for _, t := range tags { 84 v, ok := ft.Tag.Lookup(t) 85 if !ok { 86 continue 87 } 88 idx := strings.IndexFunc(v, unicode.IsPunct) 89 if idx != -1 { 90 v = v[:idx] 91 } 92 if r.byTag[t] == nil { 93 r.byTag[t] = Fields{} 94 } 95 r.byTag[t][v] = fi 96 } 97 } 98 99 return r 100 } 101 102 func (r *Reflector) Load(m kit.Message, tags ...string) *Reflected { 103 mType := reflect.Indirect(reflect.ValueOf(m)).Type() 104 cachedData := registered[mType] 105 if cachedData == nil { 106 r.cacheMtx.RLock() 107 cachedData = r.cache[mType] 108 r.cacheMtx.RUnlock() 109 if cachedData == nil { 110 cachedData = destruct(mType, tags...) 111 r.cacheMtx.Lock() 112 r.cache[mType] = cachedData 113 r.cacheMtx.Unlock() 114 } 115 } 116 117 return cachedData 118 } 119 120 func (r *Reflector) Get(m kit.Message, fieldName string) (any, error) { 121 e, err := getValue(m) 122 if err != nil { 123 return nil, err 124 } 125 126 f, ok := e.Type().FieldByName(fieldName) 127 if !ok { 128 return nil, ErrNoField 129 } 130 if f.PkgPath != "" { 131 return nil, ErrNotExported 132 } 133 134 return e.FieldByName(fieldName).Interface(), nil 135 } 136 137 func (r *Reflector) GetString(m kit.Message, fieldName string) (string, error) { 138 e, err := getValue(m) 139 if err != nil { 140 return "", err 141 } 142 f, ok := e.Type().FieldByName(fieldName) 143 if !ok { 144 return "", ErrNoField 145 } 146 if f.PkgPath != "" { 147 return "", ErrNotExported 148 } 149 150 return e.FieldByName(fieldName).String(), nil 151 } 152 153 func (r *Reflector) GetInt(m kit.Message, fieldName string) (int64, error) { 154 e, err := getValue(m) 155 if err != nil { 156 return 0, err 157 } 158 f, ok := e.Type().FieldByName(fieldName) 159 if !ok { 160 return 0, ErrNoField 161 } 162 if f.PkgPath != "" { 163 return 0, ErrNotExported 164 } 165 166 return e.FieldByName(fieldName).Int(), nil 167 }