util.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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 scan
  15. import (
  16. "errors"
  17. "reflect"
  18. "strings"
  19. "sync"
  20. )
  21. type fieldSpec struct {
  22. name string
  23. index []int
  24. omitEmpty bool
  25. }
  26. type structSpec struct {
  27. m map[string]*fieldSpec
  28. l []*fieldSpec
  29. }
  30. func (ss *structSpec) fieldSpec(name []byte) *fieldSpec {
  31. return ss.m[string(name)]
  32. }
  33. func compileStructSpec(t reflect.Type, depth map[string]int, index []int, ss *structSpec) {
  34. for i := 0; i < t.NumField(); i++ {
  35. f := t.Field(i)
  36. switch {
  37. case f.PkgPath != "":
  38. // Ignore unexported fields.
  39. case f.Anonymous:
  40. // TODO: Handle pointers. Requires change to decoder and
  41. // protection against infinite recursion.
  42. if f.Type.Kind() == reflect.Struct {
  43. compileStructSpec(f.Type, depth, append(index, i), ss)
  44. }
  45. default:
  46. fs := &fieldSpec{name: f.Name}
  47. tag := f.Tag.Get("redis")
  48. p := strings.Split(tag, ",")
  49. if len(p) > 0 && p[0] != "-" {
  50. if len(p[0]) > 0 {
  51. fs.name = p[0]
  52. }
  53. for _, s := range p[1:] {
  54. switch s {
  55. case "omitempty":
  56. fs.omitEmpty = true
  57. default:
  58. panic(errors.New("redigo: unknown field flag " + s + " for type " + t.Name()))
  59. }
  60. }
  61. }
  62. d, found := depth[fs.name]
  63. if !found {
  64. d = 1 << 30
  65. }
  66. switch {
  67. case len(index) == d:
  68. // At same depth, remove from result.
  69. delete(ss.m, fs.name)
  70. j := 0
  71. for i := 0; i < len(ss.l); i++ {
  72. if fs.name != ss.l[i].name {
  73. ss.l[j] = ss.l[i]
  74. j += 1
  75. }
  76. }
  77. ss.l = ss.l[:j]
  78. case len(index) < d:
  79. fs.index = make([]int, len(index)+1)
  80. copy(fs.index, index)
  81. fs.index[len(index)] = i
  82. depth[fs.name] = len(index)
  83. ss.m[fs.name] = fs
  84. ss.l = append(ss.l, fs)
  85. }
  86. }
  87. }
  88. }
  89. var (
  90. structSpecMutex sync.RWMutex
  91. structSpecCache = make(map[reflect.Type]*structSpec)
  92. defaultFieldSpec = &fieldSpec{}
  93. )
  94. func structSpecForType(t reflect.Type) *structSpec {
  95. structSpecMutex.RLock()
  96. ss, found := structSpecCache[t]
  97. structSpecMutex.RUnlock()
  98. if found {
  99. return ss
  100. }
  101. structSpecMutex.Lock()
  102. defer structSpecMutex.Unlock()
  103. ss, found = structSpecCache[t]
  104. if found {
  105. return ss
  106. }
  107. ss = &structSpec{m: make(map[string]*fieldSpec)}
  108. compileStructSpec(t, make(map[string]int), nil, ss)
  109. structSpecCache[t] = ss
  110. return ss
  111. }