struct.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Copyright 2012 Gary Burd
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package redisx
  15. import (
  16. "errors"
  17. "reflect"
  18. "strconv"
  19. )
  20. // ScanStruct is deprecated. Use redis.ScanStruct instead.
  21. //
  22. // ScanStruct scans a reply containing alternating names and values to a
  23. // struct. The HGETALL and CONFIG GET commands return replies in this format.
  24. //
  25. // ScanStruct uses the struct field name to match values in the response. Use
  26. // 'redis' field tag to override the name:
  27. //
  28. // Field int `redis:"myName"`
  29. //
  30. // Fields with the tag redis:"-" are ignored.
  31. func ScanStruct(reply interface{}, dst interface{}) error {
  32. v := reflect.ValueOf(dst)
  33. if v.Kind() != reflect.Ptr || v.IsNil() {
  34. return errors.New("redigo: ScanStruct value must be non-nil pointer")
  35. }
  36. v = v.Elem()
  37. ss := structSpecForType(v.Type())
  38. p, ok := reply.([]interface{})
  39. if !ok {
  40. return errors.New("redigo: ScanStruct expectes multibulk reply")
  41. }
  42. if len(p)%2 != 0 {
  43. return errors.New("redigo: ScanStruct expects even number of values in reply")
  44. }
  45. for i := 0; i < len(p); i += 2 {
  46. name, ok := p[i].([]byte)
  47. if !ok {
  48. return errors.New("redigo: ScanStruct key not a bulk value")
  49. }
  50. value, ok := p[i+1].([]byte)
  51. if !ok {
  52. return errors.New("redigo: ScanStruct value not a bulk value")
  53. }
  54. fs := ss.fieldSpec(name)
  55. if fs == nil {
  56. continue
  57. }
  58. fv := v.FieldByIndex(fs.index)
  59. switch fv.Type().Kind() {
  60. case reflect.String:
  61. fv.SetString(string(value))
  62. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  63. x, err := strconv.ParseInt(string(value), 10, fv.Type().Bits())
  64. if err != nil {
  65. return err
  66. }
  67. fv.SetInt(x)
  68. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  69. x, err := strconv.ParseUint(string(value), 10, fv.Type().Bits())
  70. if err != nil {
  71. return err
  72. }
  73. fv.SetUint(x)
  74. case reflect.Float32, reflect.Float64:
  75. x, err := strconv.ParseFloat(string(value), fv.Type().Bits())
  76. if err != nil {
  77. return err
  78. }
  79. fv.SetFloat(x)
  80. case reflect.Bool:
  81. x := len(value) != 0 && (len(value) != 1 || value[0] != '0')
  82. fv.SetBool(x)
  83. case reflect.Slice:
  84. if fv.Type().Elem().Kind() != reflect.Uint8 {
  85. // TODO: check field types in structSpec
  86. panic("redigo: unsuported type for field " + string(name))
  87. }
  88. fv.SetBytes(value)
  89. default:
  90. // TODO: check field types in structSpec
  91. panic("redigo: unsuported type for field " + string(name))
  92. }
  93. }
  94. return nil
  95. }
  96. // AppendStruct is deprecated. Use redis.Args{}.AddFlat() instead.
  97. func AppendStruct(args []interface{}, src interface{}) []interface{} {
  98. v := reflect.ValueOf(src)
  99. if v.Kind() == reflect.Ptr {
  100. if v.IsNil() {
  101. panic("redigo: FormatStruct argument must not be nil")
  102. }
  103. v = v.Elem()
  104. }
  105. if v.Kind() != reflect.Struct {
  106. panic("redigo: FormatStruct argument must be a struct or pointer to a struct")
  107. }
  108. ss := structSpecForType(v.Type())
  109. for _, fs := range ss.l {
  110. fv := v.FieldByIndex(fs.index)
  111. args = append(args, fs.name, fv.Interface())
  112. }
  113. return args
  114. }