utils.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. package mapping
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "math"
  7. "reflect"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "git.i2edu.net/i2/go-zero/core/stringx"
  12. )
  13. const (
  14. defaultOption = "default"
  15. stringOption = "string"
  16. optionalOption = "optional"
  17. optionsOption = "options"
  18. rangeOption = "range"
  19. optionSeparator = "|"
  20. equalToken = "="
  21. )
  22. var (
  23. errUnsupportedType = errors.New("unsupported type on setting field value")
  24. errNumberRange = errors.New("wrong number range setting")
  25. optionsCache = make(map[string]optionsCacheValue)
  26. cacheLock sync.RWMutex
  27. structRequiredCache = make(map[reflect.Type]requiredCacheValue)
  28. structCacheLock sync.RWMutex
  29. )
  30. type (
  31. optionsCacheValue struct {
  32. key string
  33. options *fieldOptions
  34. err error
  35. }
  36. requiredCacheValue struct {
  37. required bool
  38. err error
  39. }
  40. )
  41. // Deref dereferences a type, if pointer type, returns its element type.
  42. func Deref(t reflect.Type) reflect.Type {
  43. if t.Kind() == reflect.Ptr {
  44. t = t.Elem()
  45. }
  46. return t
  47. }
  48. // Repr returns the string representation of v.
  49. func Repr(v interface{}) string {
  50. if v == nil {
  51. return ""
  52. }
  53. // if func (v *Type) String() string, we can't use Elem()
  54. switch vt := v.(type) {
  55. case fmt.Stringer:
  56. return vt.String()
  57. }
  58. val := reflect.ValueOf(v)
  59. if val.Kind() == reflect.Ptr && !val.IsNil() {
  60. val = val.Elem()
  61. }
  62. return reprOfValue(val)
  63. }
  64. // ValidatePtr validates v if it's a valid pointer.
  65. func ValidatePtr(v *reflect.Value) error {
  66. // sequence is very important, IsNil must be called after checking Kind() with reflect.Ptr,
  67. // panic otherwise
  68. if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() {
  69. return fmt.Errorf("not a valid pointer: %v", v)
  70. }
  71. return nil
  72. }
  73. func convertType(kind reflect.Kind, str string) (interface{}, error) {
  74. switch kind {
  75. case reflect.Bool:
  76. return str == "1" || strings.ToLower(str) == "true", nil
  77. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  78. intValue, err := strconv.ParseInt(str, 10, 64)
  79. if err != nil {
  80. return 0, fmt.Errorf("the value %q cannot parsed as int", str)
  81. }
  82. return intValue, nil
  83. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  84. uintValue, err := strconv.ParseUint(str, 10, 64)
  85. if err != nil {
  86. return 0, fmt.Errorf("the value %q cannot parsed as uint", str)
  87. }
  88. return uintValue, nil
  89. case reflect.Float32, reflect.Float64:
  90. floatValue, err := strconv.ParseFloat(str, 64)
  91. if err != nil {
  92. return 0, fmt.Errorf("the value %q cannot parsed as float", str)
  93. }
  94. return floatValue, nil
  95. case reflect.String:
  96. return str, nil
  97. default:
  98. return nil, errUnsupportedType
  99. }
  100. }
  101. func doParseKeyAndOptions(field reflect.StructField, value string) (string, *fieldOptions, error) {
  102. segments := strings.Split(value, ",")
  103. key := strings.TrimSpace(segments[0])
  104. options := segments[1:]
  105. if len(options) == 0 {
  106. return key, nil, nil
  107. }
  108. var fieldOpts fieldOptions
  109. for _, segment := range options {
  110. option := strings.TrimSpace(segment)
  111. if err := parseOption(&fieldOpts, field.Name, option); err != nil {
  112. return "", nil, err
  113. }
  114. }
  115. return key, &fieldOpts, nil
  116. }
  117. func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {
  118. numFields := tp.NumField()
  119. for i := 0; i < numFields; i++ {
  120. childField := tp.Field(i)
  121. if usingDifferentKeys(tag, childField) {
  122. return true, nil
  123. }
  124. _, opts, err := parseKeyAndOptions(tag, childField)
  125. if err != nil {
  126. return false, err
  127. }
  128. if opts == nil {
  129. if childField.Type.Kind() != reflect.Struct {
  130. return true, nil
  131. }
  132. if required, err := implicitValueRequiredStruct(tag, childField.Type); err != nil {
  133. return false, err
  134. } else if required {
  135. return true, nil
  136. }
  137. } else if !opts.Optional && len(opts.Default) == 0 {
  138. return true, nil
  139. } else if len(opts.OptionalDep) > 0 && opts.OptionalDep[0] == notSymbol {
  140. return true, nil
  141. }
  142. }
  143. return false, nil
  144. }
  145. func isLeftInclude(b byte) (bool, error) {
  146. switch b {
  147. case '[':
  148. return true, nil
  149. case '(':
  150. return false, nil
  151. default:
  152. return false, errNumberRange
  153. }
  154. }
  155. func isRightInclude(b byte) (bool, error) {
  156. switch b {
  157. case ']':
  158. return true, nil
  159. case ')':
  160. return false, nil
  161. default:
  162. return false, errNumberRange
  163. }
  164. }
  165. func maybeNewValue(field reflect.StructField, value reflect.Value) {
  166. if field.Type.Kind() == reflect.Ptr && value.IsNil() {
  167. value.Set(reflect.New(value.Type().Elem()))
  168. }
  169. }
  170. // don't modify returned fieldOptions, it's cached and shared among different calls.
  171. func parseKeyAndOptions(tagName string, field reflect.StructField) (string, *fieldOptions, error) {
  172. value := field.Tag.Get(tagName)
  173. if len(value) == 0 {
  174. return field.Name, nil, nil
  175. }
  176. cacheLock.RLock()
  177. cache, ok := optionsCache[value]
  178. cacheLock.RUnlock()
  179. if ok {
  180. return stringx.TakeOne(cache.key, field.Name), cache.options, cache.err
  181. }
  182. key, options, err := doParseKeyAndOptions(field, value)
  183. cacheLock.Lock()
  184. optionsCache[value] = optionsCacheValue{
  185. key: key,
  186. options: options,
  187. err: err,
  188. }
  189. cacheLock.Unlock()
  190. return stringx.TakeOne(key, field.Name), options, err
  191. }
  192. // support below notations:
  193. // [:5] (:5] [:5) (:5)
  194. // [1:] [1:) (1:] (1:)
  195. // [1:5] [1:5) (1:5] (1:5)
  196. func parseNumberRange(str string) (*numberRange, error) {
  197. if len(str) == 0 {
  198. return nil, errNumberRange
  199. }
  200. leftInclude, err := isLeftInclude(str[0])
  201. if err != nil {
  202. return nil, err
  203. }
  204. str = str[1:]
  205. if len(str) == 0 {
  206. return nil, errNumberRange
  207. }
  208. rightInclude, err := isRightInclude(str[len(str)-1])
  209. if err != nil {
  210. return nil, err
  211. }
  212. str = str[:len(str)-1]
  213. fields := strings.Split(str, ":")
  214. if len(fields) != 2 {
  215. return nil, errNumberRange
  216. }
  217. if len(fields[0]) == 0 && len(fields[1]) == 0 {
  218. return nil, errNumberRange
  219. }
  220. var left float64
  221. if len(fields[0]) > 0 {
  222. var err error
  223. if left, err = strconv.ParseFloat(fields[0], 64); err != nil {
  224. return nil, err
  225. }
  226. } else {
  227. left = -math.MaxFloat64
  228. }
  229. var right float64
  230. if len(fields[1]) > 0 {
  231. var err error
  232. if right, err = strconv.ParseFloat(fields[1], 64); err != nil {
  233. return nil, err
  234. }
  235. } else {
  236. right = math.MaxFloat64
  237. }
  238. return &numberRange{
  239. left: left,
  240. leftInclude: leftInclude,
  241. right: right,
  242. rightInclude: rightInclude,
  243. }, nil
  244. }
  245. func parseOption(fieldOpts *fieldOptions, fieldName, option string) error {
  246. switch {
  247. case option == stringOption:
  248. fieldOpts.FromString = true
  249. case strings.HasPrefix(option, optionalOption):
  250. segs := strings.Split(option, equalToken)
  251. switch len(segs) {
  252. case 1:
  253. fieldOpts.Optional = true
  254. case 2:
  255. fieldOpts.Optional = true
  256. fieldOpts.OptionalDep = segs[1]
  257. default:
  258. return fmt.Errorf("field %s has wrong optional", fieldName)
  259. }
  260. case option == optionalOption:
  261. fieldOpts.Optional = true
  262. case strings.HasPrefix(option, optionsOption):
  263. segs := strings.Split(option, equalToken)
  264. if len(segs) != 2 {
  265. return fmt.Errorf("field %s has wrong options", fieldName)
  266. }
  267. fieldOpts.Options = strings.Split(segs[1], optionSeparator)
  268. case strings.HasPrefix(option, defaultOption):
  269. segs := strings.Split(option, equalToken)
  270. if len(segs) != 2 {
  271. return fmt.Errorf("field %s has wrong default option", fieldName)
  272. }
  273. fieldOpts.Default = strings.TrimSpace(segs[1])
  274. case strings.HasPrefix(option, rangeOption):
  275. segs := strings.Split(option, equalToken)
  276. if len(segs) != 2 {
  277. return fmt.Errorf("field %s has wrong range", fieldName)
  278. }
  279. nr, err := parseNumberRange(segs[1])
  280. if err != nil {
  281. return err
  282. }
  283. fieldOpts.Range = nr
  284. }
  285. return nil
  286. }
  287. func reprOfValue(val reflect.Value) string {
  288. switch vt := val.Interface().(type) {
  289. case bool:
  290. return strconv.FormatBool(vt)
  291. case error:
  292. return vt.Error()
  293. case float32:
  294. return strconv.FormatFloat(float64(vt), 'f', -1, 32)
  295. case float64:
  296. return strconv.FormatFloat(vt, 'f', -1, 64)
  297. case fmt.Stringer:
  298. return vt.String()
  299. case int:
  300. return strconv.Itoa(vt)
  301. case int8:
  302. return strconv.Itoa(int(vt))
  303. case int16:
  304. return strconv.Itoa(int(vt))
  305. case int32:
  306. return strconv.Itoa(int(vt))
  307. case int64:
  308. return strconv.FormatInt(vt, 10)
  309. case string:
  310. return vt
  311. case uint:
  312. return strconv.FormatUint(uint64(vt), 10)
  313. case uint8:
  314. return strconv.FormatUint(uint64(vt), 10)
  315. case uint16:
  316. return strconv.FormatUint(uint64(vt), 10)
  317. case uint32:
  318. return strconv.FormatUint(uint64(vt), 10)
  319. case uint64:
  320. return strconv.FormatUint(vt, 10)
  321. case []byte:
  322. return string(vt)
  323. default:
  324. return fmt.Sprint(val.Interface())
  325. }
  326. }
  327. func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v interface{}) error {
  328. switch kind {
  329. case reflect.Bool:
  330. value.SetBool(v.(bool))
  331. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  332. value.SetInt(v.(int64))
  333. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  334. value.SetUint(v.(uint64))
  335. case reflect.Float32, reflect.Float64:
  336. value.SetFloat(v.(float64))
  337. case reflect.String:
  338. value.SetString(v.(string))
  339. default:
  340. return errUnsupportedType
  341. }
  342. return nil
  343. }
  344. func setValue(kind reflect.Kind, value reflect.Value, str string) error {
  345. if !value.CanSet() {
  346. return errValueNotSettable
  347. }
  348. v, err := convertType(kind, str)
  349. if err != nil {
  350. return err
  351. }
  352. return setMatchedPrimitiveValue(kind, value, v)
  353. }
  354. func structValueRequired(tag string, tp reflect.Type) (bool, error) {
  355. structCacheLock.RLock()
  356. val, ok := structRequiredCache[tp]
  357. structCacheLock.RUnlock()
  358. if ok {
  359. return val.required, val.err
  360. }
  361. required, err := implicitValueRequiredStruct(tag, tp)
  362. structCacheLock.Lock()
  363. structRequiredCache[tp] = requiredCacheValue{
  364. required: required,
  365. err: err,
  366. }
  367. structCacheLock.Unlock()
  368. return required, err
  369. }
  370. func toFloat64(v interface{}) (float64, bool) {
  371. switch val := v.(type) {
  372. case int:
  373. return float64(val), true
  374. case int8:
  375. return float64(val), true
  376. case int16:
  377. return float64(val), true
  378. case int32:
  379. return float64(val), true
  380. case int64:
  381. return float64(val), true
  382. case uint:
  383. return float64(val), true
  384. case uint8:
  385. return float64(val), true
  386. case uint16:
  387. return float64(val), true
  388. case uint32:
  389. return float64(val), true
  390. case uint64:
  391. return float64(val), true
  392. case float32:
  393. return float64(val), true
  394. case float64:
  395. return val, true
  396. default:
  397. return 0, false
  398. }
  399. }
  400. func usingDifferentKeys(key string, field reflect.StructField) bool {
  401. if len(field.Tag) > 0 {
  402. if _, ok := field.Tag.Lookup(key); !ok {
  403. return true
  404. }
  405. }
  406. return false
  407. }
  408. func validateAndSetValue(kind reflect.Kind, value reflect.Value, str string, opts *fieldOptionsWithContext) error {
  409. if !value.CanSet() {
  410. return errValueNotSettable
  411. }
  412. v, err := convertType(kind, str)
  413. if err != nil {
  414. return err
  415. }
  416. if err := validateValueRange(v, opts); err != nil {
  417. return err
  418. }
  419. return setMatchedPrimitiveValue(kind, value, v)
  420. }
  421. func validateJsonNumberRange(v json.Number, opts *fieldOptionsWithContext) error {
  422. if opts == nil || opts.Range == nil {
  423. return nil
  424. }
  425. fv, err := v.Float64()
  426. if err != nil {
  427. return err
  428. }
  429. return validateNumberRange(fv, opts.Range)
  430. }
  431. func validateNumberRange(fv float64, nr *numberRange) error {
  432. if nr == nil {
  433. return nil
  434. }
  435. if (nr.leftInclude && fv < nr.left) || (!nr.leftInclude && fv <= nr.left) {
  436. return errNumberRange
  437. }
  438. if (nr.rightInclude && fv > nr.right) || (!nr.rightInclude && fv >= nr.right) {
  439. return errNumberRange
  440. }
  441. return nil
  442. }
  443. func validateValueInOptions(options []string, value interface{}) error {
  444. if len(options) > 0 {
  445. switch v := value.(type) {
  446. case string:
  447. if !stringx.Contains(options, v) {
  448. return fmt.Errorf(`error: value "%s" is not defined in options "%v"`, v, options)
  449. }
  450. default:
  451. if !stringx.Contains(options, Repr(v)) {
  452. return fmt.Errorf(`error: value "%v" is not defined in options "%v"`, value, options)
  453. }
  454. }
  455. }
  456. return nil
  457. }
  458. func validateValueRange(mapValue interface{}, opts *fieldOptionsWithContext) error {
  459. if opts == nil || opts.Range == nil {
  460. return nil
  461. }
  462. fv, ok := toFloat64(mapValue)
  463. if !ok {
  464. return errNumberRange
  465. }
  466. return validateNumberRange(fv, opts.Range)
  467. }