You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
3.4 KiB

  1. package proto
  2. import (
  3. "encoding"
  4. "fmt"
  5. "reflect"
  6. "time"
  7. "github.com/go-redis/redis/v8/internal/util"
  8. )
  9. // Scan parses bytes `b` to `v` with appropriate type.
  10. //nolint:gocyclo
  11. func Scan(b []byte, v interface{}) error {
  12. switch v := v.(type) {
  13. case nil:
  14. return fmt.Errorf("redis: Scan(nil)")
  15. case *string:
  16. *v = util.BytesToString(b)
  17. return nil
  18. case *[]byte:
  19. *v = b
  20. return nil
  21. case *int:
  22. var err error
  23. *v, err = util.Atoi(b)
  24. return err
  25. case *int8:
  26. n, err := util.ParseInt(b, 10, 8)
  27. if err != nil {
  28. return err
  29. }
  30. *v = int8(n)
  31. return nil
  32. case *int16:
  33. n, err := util.ParseInt(b, 10, 16)
  34. if err != nil {
  35. return err
  36. }
  37. *v = int16(n)
  38. return nil
  39. case *int32:
  40. n, err := util.ParseInt(b, 10, 32)
  41. if err != nil {
  42. return err
  43. }
  44. *v = int32(n)
  45. return nil
  46. case *int64:
  47. n, err := util.ParseInt(b, 10, 64)
  48. if err != nil {
  49. return err
  50. }
  51. *v = n
  52. return nil
  53. case *uint:
  54. n, err := util.ParseUint(b, 10, 64)
  55. if err != nil {
  56. return err
  57. }
  58. *v = uint(n)
  59. return nil
  60. case *uint8:
  61. n, err := util.ParseUint(b, 10, 8)
  62. if err != nil {
  63. return err
  64. }
  65. *v = uint8(n)
  66. return nil
  67. case *uint16:
  68. n, err := util.ParseUint(b, 10, 16)
  69. if err != nil {
  70. return err
  71. }
  72. *v = uint16(n)
  73. return nil
  74. case *uint32:
  75. n, err := util.ParseUint(b, 10, 32)
  76. if err != nil {
  77. return err
  78. }
  79. *v = uint32(n)
  80. return nil
  81. case *uint64:
  82. n, err := util.ParseUint(b, 10, 64)
  83. if err != nil {
  84. return err
  85. }
  86. *v = n
  87. return nil
  88. case *float32:
  89. n, err := util.ParseFloat(b, 32)
  90. if err != nil {
  91. return err
  92. }
  93. *v = float32(n)
  94. return err
  95. case *float64:
  96. var err error
  97. *v, err = util.ParseFloat(b, 64)
  98. return err
  99. case *bool:
  100. *v = len(b) == 1 && b[0] == '1'
  101. return nil
  102. case *time.Time:
  103. var err error
  104. *v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b))
  105. return err
  106. case *time.Duration:
  107. n, err := util.ParseInt(b, 10, 64)
  108. if err != nil {
  109. return err
  110. }
  111. *v = time.Duration(n)
  112. return nil
  113. case encoding.BinaryUnmarshaler:
  114. return v.UnmarshalBinary(b)
  115. default:
  116. return fmt.Errorf(
  117. "redis: can't unmarshal %T (consider implementing BinaryUnmarshaler)", v)
  118. }
  119. }
  120. func ScanSlice(data []string, slice interface{}) error {
  121. v := reflect.ValueOf(slice)
  122. if !v.IsValid() {
  123. return fmt.Errorf("redis: ScanSlice(nil)")
  124. }
  125. if v.Kind() != reflect.Ptr {
  126. return fmt.Errorf("redis: ScanSlice(non-pointer %T)", slice)
  127. }
  128. v = v.Elem()
  129. if v.Kind() != reflect.Slice {
  130. return fmt.Errorf("redis: ScanSlice(non-slice %T)", slice)
  131. }
  132. next := makeSliceNextElemFunc(v)
  133. for i, s := range data {
  134. elem := next()
  135. if err := Scan([]byte(s), elem.Addr().Interface()); err != nil {
  136. err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %w", i, s, err)
  137. return err
  138. }
  139. }
  140. return nil
  141. }
  142. func makeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
  143. elemType := v.Type().Elem()
  144. if elemType.Kind() == reflect.Ptr {
  145. elemType = elemType.Elem()
  146. return func() reflect.Value {
  147. if v.Len() < v.Cap() {
  148. v.Set(v.Slice(0, v.Len()+1))
  149. elem := v.Index(v.Len() - 1)
  150. if elem.IsNil() {
  151. elem.Set(reflect.New(elemType))
  152. }
  153. return elem.Elem()
  154. }
  155. elem := reflect.New(elemType)
  156. v.Set(reflect.Append(v, elem))
  157. return elem.Elem()
  158. }
  159. }
  160. zero := reflect.Zero(elemType)
  161. return func() reflect.Value {
  162. if v.Len() < v.Cap() {
  163. v.Set(v.Slice(0, v.Len()+1))
  164. return v.Index(v.Len() - 1)
  165. }
  166. v.Set(reflect.Append(v, zero))
  167. return v.Index(v.Len() - 1)
  168. }
  169. }