http urls monitor.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. // Package reflectx implements extensions to the standard reflect lib suitable
  2. // for implementing marshaling and unmarshaling packages. The main Mapper type
  3. // allows for Go-compatible named attribute access, including accessing embedded
  4. // struct attributes and the ability to use functions and struct tags to
  5. // customize field names.
  6. //
  7. package reflectx
  8. import (
  9. "fmt"
  10. "reflect"
  11. "runtime"
  12. "strings"
  13. "sync"
  14. )
  15. // A FieldInfo is a collection of metadata about a struct field.
  16. type FieldInfo struct {
  17. Index []int
  18. Path string
  19. Field reflect.StructField
  20. Zero reflect.Value
  21. Name string
  22. Options map[string]string
  23. Embedded bool
  24. Children []*FieldInfo
  25. Parent *FieldInfo
  26. }
  27. // A StructMap is an index of field metadata for a struct.
  28. type StructMap struct {
  29. Tree *FieldInfo
  30. Index []*FieldInfo
  31. Paths map[string]*FieldInfo
  32. Names map[string]*FieldInfo
  33. }
  34. // GetByPath returns a *FieldInfo for a given string path.
  35. func (f StructMap) GetByPath(path string) *FieldInfo {
  36. return f.Paths[path]
  37. }
  38. // GetByTraversal returns a *FieldInfo for a given integer path. It is
  39. // analogous to reflect.FieldByIndex.
  40. func (f StructMap) GetByTraversal(index []int) *FieldInfo {
  41. if len(index) == 0 {
  42. return nil
  43. }
  44. tree := f.Tree
  45. for _, i := range index {
  46. if i >= len(tree.Children) || tree.Children[i] == nil {
  47. return nil
  48. }
  49. tree = tree.Children[i]
  50. }
  51. return tree
  52. }
  53. // Mapper is a general purpose mapper of names to struct fields. A Mapper
  54. // behaves like most marshallers, optionally obeying a field tag for name
  55. // mapping and a function to provide a basic mapping of fields to names.
  56. type Mapper struct {
  57. cache map[reflect.Type]*StructMap
  58. tagName string
  59. tagMapFunc func(string) string
  60. mapFunc func(string) string
  61. mutex sync.Mutex
  62. }
  63. // NewMapper returns a new mapper which optionally obeys the field tag given
  64. // by tagName. If tagName is the empty string, it is ignored.
  65. func NewMapper(tagName string) *Mapper {
  66. return &Mapper{
  67. cache: make(map[reflect.Type]*StructMap),
  68. tagName: tagName,
  69. }
  70. }
  71. // NewMapperTagFunc returns a new mapper which contains a mapper for field names
  72. // AND a mapper for tag values. This is useful for tags like json which can
  73. // have values like "name,omitempty".
  74. func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper {
  75. return &Mapper{
  76. cache: make(map[reflect.Type]*StructMap),
  77. tagName: tagName,
  78. mapFunc: mapFunc,
  79. tagMapFunc: tagMapFunc,
  80. }
  81. }
  82. // NewMapperFunc returns a new mapper which optionally obeys a field tag and
  83. // a struct field name mapper func given by f. Tags will take precedence, but
  84. // for any other field, the mapped name will be f(field.Name)
  85. func NewMapperFunc(tagName string, f func(string) string) *Mapper {
  86. return &Mapper{
  87. cache: make(map[reflect.Type]*StructMap),
  88. tagName: tagName,
  89. mapFunc: f,
  90. }
  91. }
  92. // TypeMap returns a mapping of field strings to int slices representing
  93. // the traversal down the struct to reach the field.
  94. func (m *Mapper) TypeMap(t reflect.Type) *StructMap {
  95. m.mutex.Lock()
  96. mapping, ok := m.cache[t]
  97. if !ok {
  98. mapping = getMapping(t, m.tagName, m.mapFunc, m.tagMapFunc)
  99. m.cache[t] = mapping
  100. }
  101. m.mutex.Unlock()
  102. return mapping
  103. }
  104. // FieldMap returns the mapper's mapping of field names to reflect values. Panics
  105. // if v's Kind is not Struct, or v is not Indirectable to a struct kind.
  106. func (m *Mapper) FieldMap(v reflect.Value) map[string]reflect.Value {
  107. v = reflect.Indirect(v)
  108. mustBe(v, reflect.Struct)
  109. r := map[string]reflect.Value{}
  110. tm := m.TypeMap(v.Type())
  111. for tagName, fi := range tm.Names {
  112. r[tagName] = FieldByIndexes(v, fi.Index)
  113. }
  114. return r
  115. }
  116. // ValidFieldMap returns the mapper's mapping of field names to reflect valid
  117. // field values. Panics if v's Kind is not Struct, or v is not Indirectable to
  118. // a struct kind.
  119. func (m *Mapper) ValidFieldMap(v reflect.Value) map[string]reflect.Value {
  120. v = reflect.Indirect(v)
  121. mustBe(v, reflect.Struct)
  122. r := map[string]reflect.Value{}
  123. tm := m.TypeMap(v.Type())
  124. for tagName, fi := range tm.Names {
  125. v := ValidFieldByIndexes(v, fi.Index)
  126. if v.IsValid() {
  127. r[tagName] = v
  128. }
  129. }
  130. return r
  131. }
  132. // FieldByName returns a field by the its mapped name as a reflect.Value.
  133. // Panics if v's Kind is not Struct or v is not Indirectable to a struct Kind.
  134. // Returns zero Value if the name is not found.
  135. func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value {
  136. v = reflect.Indirect(v)
  137. mustBe(v, reflect.Struct)
  138. tm := m.TypeMap(v.Type())
  139. fi, ok := tm.Names[name]
  140. if !ok {
  141. return v
  142. }
  143. return FieldByIndexes(v, fi.Index)
  144. }
  145. // FieldsByName returns a slice of values corresponding to the slice of names
  146. // for the value. Panics if v's Kind is not Struct or v is not Indirectable
  147. // to a struct Kind. Returns zero Value for each name not found.
  148. func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value {
  149. v = reflect.Indirect(v)
  150. mustBe(v, reflect.Struct)
  151. tm := m.TypeMap(v.Type())
  152. vals := make([]reflect.Value, 0, len(names))
  153. for _, name := range names {
  154. fi, ok := tm.Names[name]
  155. if !ok {
  156. vals = append(vals, *new(reflect.Value))
  157. } else {
  158. vals = append(vals, FieldByIndexes(v, fi.Index))
  159. }
  160. }
  161. return vals
  162. }
  163. // TraversalsByName returns a slice of int slices which represent the struct
  164. // traversals for each mapped name. Panics if t is not a struct or Indirectable
  165. // to a struct. Returns empty int slice for each name not found.
  166. func (m *Mapper) TraversalsByName(t reflect.Type, names []string) [][]int {
  167. t = Deref(t)
  168. mustBe(t, reflect.Struct)
  169. tm := m.TypeMap(t)
  170. r := make([][]int, 0, len(names))
  171. for _, name := range names {
  172. fi, ok := tm.Names[name]
  173. if !ok {
  174. r = append(r, []int{})
  175. } else {
  176. r = append(r, fi.Index)
  177. }
  178. }
  179. return r
  180. }
  181. // FieldByIndexes returns a value for a particular struct traversal.
  182. func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value {
  183. for _, i := range indexes {
  184. v = reflect.Indirect(v).Field(i)
  185. // if this is a pointer, it's possible it is nil
  186. if v.Kind() == reflect.Ptr && v.IsNil() {
  187. alloc := reflect.New(Deref(v.Type()))
  188. v.Set(alloc)
  189. }
  190. if v.Kind() == reflect.Map && v.IsNil() {
  191. v.Set(reflect.MakeMap(v.Type()))
  192. }
  193. }
  194. return v
  195. }
  196. // ValidFieldByIndexes returns a value for a particular struct traversal.
  197. func ValidFieldByIndexes(v reflect.Value, indexes []int) reflect.Value {
  198. for _, i := range indexes {
  199. v = reflect.Indirect(v)
  200. if !v.IsValid() {
  201. return reflect.Value{}
  202. }
  203. v = v.Field(i)
  204. // if this is a pointer, it's possible it is nil
  205. if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Map) && v.IsNil() {
  206. return reflect.Value{}
  207. }
  208. }
  209. return v
  210. }
  211. // FieldByIndexesReadOnly returns a value for a particular struct traversal,
  212. // but is not concerned with allocating nil pointers because the value is
  213. // going to be used for reading and not setting.
  214. func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value {
  215. for _, i := range indexes {
  216. v = reflect.Indirect(v).Field(i)
  217. }
  218. return v
  219. }
  220. // Deref is Indirect for reflect.Types
  221. func Deref(t reflect.Type) reflect.Type {
  222. if t.Kind() == reflect.Ptr {
  223. t = t.Elem()
  224. }
  225. return t
  226. }
  227. // -- helpers & utilities --
  228. type kinder interface {
  229. Kind() reflect.Kind
  230. }
  231. // mustBe checks a value against a kind, panicing with a reflect.ValueError
  232. // if the kind isn't that which is required.
  233. func mustBe(v kinder, expected reflect.Kind) {
  234. k := v.Kind()
  235. if k != expected {
  236. panic(&reflect.ValueError{Method: methodName(), Kind: k})
  237. }
  238. }
  239. // methodName is returns the caller of the function calling methodName
  240. func methodName() string {
  241. pc, _, _, _ := runtime.Caller(2)
  242. f := runtime.FuncForPC(pc)
  243. if f == nil {
  244. return "unknown method"
  245. }
  246. return f.Name()
  247. }
  248. type typeQueue struct {
  249. t reflect.Type
  250. fi *FieldInfo
  251. pp string // Parent path
  252. }
  253. // A copying append that creates a new slice each time.
  254. func apnd(is []int, i int) []int {
  255. x := make([]int, len(is)+1)
  256. for p, n := range is {
  257. x[p] = n
  258. }
  259. x[len(x)-1] = i
  260. return x
  261. }
  262. // getMapping returns a mapping for the t type, using the tagName, mapFunc and
  263. // tagMapFunc to determine the canonical names of fields.
  264. func getMapping(t reflect.Type, tagName string, mapFunc, tagMapFunc func(string) string) *StructMap {
  265. m := []*FieldInfo{}
  266. root := &FieldInfo{}
  267. queue := []typeQueue{}
  268. queue = append(queue, typeQueue{Deref(t), root, ""})
  269. for len(queue) != 0 {
  270. // pop the first item off of the queue
  271. tq := queue[0]
  272. queue = queue[1:]
  273. nChildren := 0
  274. if tq.t.Kind() == reflect.Struct {
  275. nChildren = tq.t.NumField()
  276. }
  277. tq.fi.Children = make([]*FieldInfo, nChildren)
  278. // iterate through all of its fields
  279. for fieldPos := 0; fieldPos < nChildren; fieldPos++ {
  280. f := tq.t.Field(fieldPos)
  281. fi := FieldInfo{}
  282. fi.Field = f
  283. fi.Zero = reflect.New(f.Type).Elem()
  284. fi.Options = map[string]string{}
  285. var tag, name string
  286. if tagName != "" && strings.Contains(string(f.Tag), tagName+":") {
  287. tag = f.Tag.Get(tagName)
  288. name = tag
  289. } else {
  290. if mapFunc != nil {
  291. name = mapFunc(f.Name)
  292. }
  293. }
  294. parts := strings.Split(name, ",")
  295. if len(parts) > 1 {
  296. name = parts[0]
  297. for _, opt := range parts[1:] {
  298. kv := strings.Split(opt, "=")
  299. if len(kv) > 1 {
  300. fi.Options[kv[0]] = kv[1]
  301. } else {
  302. fi.Options[kv[0]] = ""
  303. }
  304. }
  305. }
  306. if tagMapFunc != nil {
  307. tag = tagMapFunc(tag)
  308. }
  309. fi.Name = name
  310. if tq.pp == "" || (tq.pp == "" && tag == "") {
  311. fi.Path = fi.Name
  312. } else {
  313. fi.Path = fmt.Sprintf("%s.%s", tq.pp, fi.Name)
  314. }
  315. // if the name is "-", disabled via a tag, skip it
  316. if name == "-" {
  317. continue
  318. }
  319. // skip unexported fields
  320. if len(f.PkgPath) != 0 && !f.Anonymous {
  321. continue
  322. }
  323. // bfs search of anonymous embedded structs
  324. if f.Anonymous {
  325. pp := tq.pp
  326. if tag != "" {
  327. pp = fi.Path
  328. }
  329. fi.Embedded = true
  330. fi.Index = apnd(tq.fi.Index, fieldPos)
  331. nChildren := 0
  332. ft := Deref(f.Type)
  333. if ft.Kind() == reflect.Struct {
  334. nChildren = ft.NumField()
  335. }
  336. fi.Children = make([]*FieldInfo, nChildren)
  337. queue = append(queue, typeQueue{Deref(f.Type), &fi, pp})
  338. } else if fi.Zero.Kind() == reflect.Struct || (fi.Zero.Kind() == reflect.Ptr && fi.Zero.Type().Elem().Kind() == reflect.Struct) {
  339. fi.Index = apnd(tq.fi.Index, fieldPos)
  340. fi.Children = make([]*FieldInfo, Deref(f.Type).NumField())
  341. queue = append(queue, typeQueue{Deref(f.Type), &fi, fi.Path})
  342. }
  343. fi.Index = apnd(tq.fi.Index, fieldPos)
  344. fi.Parent = tq.fi
  345. tq.fi.Children[fieldPos] = &fi
  346. m = append(m, &fi)
  347. }
  348. }
  349. flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}}
  350. for _, fi := range flds.Index {
  351. flds.Paths[fi.Path] = fi
  352. if fi.Name != "" && !fi.Embedded {
  353. flds.Names[fi.Path] = fi
  354. }
  355. }
  356. return flds
  357. }