reflectwalk.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. // reflectwalk is a package that allows you to "walk" complex structures
  2. // similar to how you may "walk" a filesystem: visiting every element one
  3. // by one and calling callback functions allowing you to handle and manipulate
  4. // those elements.
  5. package reflectwalk
  6. import (
  7. "errors"
  8. "reflect"
  9. )
  10. // PrimitiveWalker implementations are able to handle primitive values
  11. // within complex structures. Primitive values are numbers, strings,
  12. // booleans, funcs, chans.
  13. //
  14. // These primitive values are often members of more complex
  15. // structures (slices, maps, etc.) that are walkable by other interfaces.
  16. type PrimitiveWalker interface {
  17. Primitive(reflect.Value) error
  18. }
  19. // InterfaceWalker implementations are able to handle interface values as they
  20. // are encountered during the walk.
  21. type InterfaceWalker interface {
  22. Interface(reflect.Value) error
  23. }
  24. // MapWalker implementations are able to handle individual elements
  25. // found within a map structure.
  26. type MapWalker interface {
  27. Map(m reflect.Value) error
  28. MapElem(m, k, v reflect.Value) error
  29. }
  30. // SliceWalker implementations are able to handle slice elements found
  31. // within complex structures.
  32. type SliceWalker interface {
  33. Slice(reflect.Value) error
  34. SliceElem(int, reflect.Value) error
  35. }
  36. // ArrayWalker implementations are able to handle array elements found
  37. // within complex structures.
  38. type ArrayWalker interface {
  39. Array(reflect.Value) error
  40. ArrayElem(int, reflect.Value) error
  41. }
  42. // StructWalker is an interface that has methods that are called for
  43. // structs when a Walk is done.
  44. type StructWalker interface {
  45. Struct(reflect.Value) error
  46. StructField(reflect.StructField, reflect.Value) error
  47. }
  48. // EnterExitWalker implementations are notified before and after
  49. // they walk deeper into complex structures (into struct fields,
  50. // into slice elements, etc.)
  51. type EnterExitWalker interface {
  52. Enter(Location) error
  53. Exit(Location) error
  54. }
  55. // PointerWalker implementations are notified when the value they're
  56. // walking is a pointer or not. Pointer is called for _every_ value whether
  57. // it is a pointer or not.
  58. type PointerWalker interface {
  59. PointerEnter(bool) error
  60. PointerExit(bool) error
  61. }
  62. // PointerValueWalker implementations are notified with the value of
  63. // a particular pointer when a pointer is walked. Pointer is called
  64. // right before PointerEnter.
  65. type PointerValueWalker interface {
  66. Pointer(reflect.Value) error
  67. }
  68. // SkipEntry can be returned from walk functions to skip walking
  69. // the value of this field. This is only valid in the following functions:
  70. //
  71. // - Struct: skips all fields from being walked
  72. // - StructField: skips walking the struct value
  73. //
  74. var SkipEntry = errors.New("skip this entry")
  75. // Walk takes an arbitrary value and an interface and traverses the
  76. // value, calling callbacks on the interface if they are supported.
  77. // The interface should implement one or more of the walker interfaces
  78. // in this package, such as PrimitiveWalker, StructWalker, etc.
  79. func Walk(data, walker interface{}) (err error) {
  80. v := reflect.ValueOf(data)
  81. ew, ok := walker.(EnterExitWalker)
  82. if ok {
  83. err = ew.Enter(WalkLoc)
  84. }
  85. if err == nil {
  86. err = walk(v, walker)
  87. }
  88. if ok && err == nil {
  89. err = ew.Exit(WalkLoc)
  90. }
  91. return
  92. }
  93. func walk(v reflect.Value, w interface{}) (err error) {
  94. // Determine if we're receiving a pointer and if so notify the walker.
  95. // The logic here is convoluted but very important (tests will fail if
  96. // almost any part is changed). I will try to explain here.
  97. //
  98. // First, we check if the value is an interface, if so, we really need
  99. // to check the interface's VALUE to see whether it is a pointer.
  100. //
  101. // Check whether the value is then a pointer. If so, then set pointer
  102. // to true to notify the user.
  103. //
  104. // If we still have a pointer or an interface after the indirections, then
  105. // we unwrap another level
  106. //
  107. // At this time, we also set "v" to be the dereferenced value. This is
  108. // because once we've unwrapped the pointer we want to use that value.
  109. pointer := false
  110. pointerV := v
  111. for {
  112. if pointerV.Kind() == reflect.Interface {
  113. if iw, ok := w.(InterfaceWalker); ok {
  114. if err = iw.Interface(pointerV); err != nil {
  115. return
  116. }
  117. }
  118. pointerV = pointerV.Elem()
  119. }
  120. if pointerV.Kind() == reflect.Ptr {
  121. if pw, ok := w.(PointerValueWalker); ok {
  122. if err = pw.Pointer(pointerV); err != nil {
  123. if err == SkipEntry {
  124. // Skip the rest of this entry but clear the error
  125. return nil
  126. }
  127. return
  128. }
  129. }
  130. pointer = true
  131. v = reflect.Indirect(pointerV)
  132. }
  133. if pw, ok := w.(PointerWalker); ok {
  134. if err = pw.PointerEnter(pointer); err != nil {
  135. return
  136. }
  137. defer func(pointer bool) {
  138. if err != nil {
  139. return
  140. }
  141. err = pw.PointerExit(pointer)
  142. }(pointer)
  143. }
  144. if pointer {
  145. pointerV = v
  146. }
  147. pointer = false
  148. // If we still have a pointer or interface we have to indirect another level.
  149. switch pointerV.Kind() {
  150. case reflect.Ptr, reflect.Interface:
  151. continue
  152. }
  153. break
  154. }
  155. // We preserve the original value here because if it is an interface
  156. // type, we want to pass that directly into the walkPrimitive, so that
  157. // we can set it.
  158. originalV := v
  159. if v.Kind() == reflect.Interface {
  160. v = v.Elem()
  161. }
  162. k := v.Kind()
  163. if k >= reflect.Int && k <= reflect.Complex128 {
  164. k = reflect.Int
  165. }
  166. switch k {
  167. // Primitives
  168. case reflect.Bool, reflect.Chan, reflect.Func, reflect.Int, reflect.String, reflect.Invalid:
  169. err = walkPrimitive(originalV, w)
  170. return
  171. case reflect.Map:
  172. err = walkMap(v, w)
  173. return
  174. case reflect.Slice:
  175. err = walkSlice(v, w)
  176. return
  177. case reflect.Struct:
  178. err = walkStruct(v, w)
  179. return
  180. case reflect.Array:
  181. err = walkArray(v, w)
  182. return
  183. default:
  184. panic("unsupported type: " + k.String())
  185. }
  186. }
  187. func walkMap(v reflect.Value, w interface{}) error {
  188. ew, ewok := w.(EnterExitWalker)
  189. if ewok {
  190. ew.Enter(Map)
  191. }
  192. if mw, ok := w.(MapWalker); ok {
  193. if err := mw.Map(v); err != nil {
  194. return err
  195. }
  196. }
  197. for _, k := range v.MapKeys() {
  198. kv := v.MapIndex(k)
  199. if mw, ok := w.(MapWalker); ok {
  200. if err := mw.MapElem(v, k, kv); err != nil {
  201. return err
  202. }
  203. }
  204. ew, ok := w.(EnterExitWalker)
  205. if ok {
  206. ew.Enter(MapKey)
  207. }
  208. if err := walk(k, w); err != nil {
  209. return err
  210. }
  211. if ok {
  212. ew.Exit(MapKey)
  213. ew.Enter(MapValue)
  214. }
  215. // get the map value again as it may have changed in the MapElem call
  216. if err := walk(v.MapIndex(k), w); err != nil {
  217. return err
  218. }
  219. if ok {
  220. ew.Exit(MapValue)
  221. }
  222. }
  223. if ewok {
  224. ew.Exit(Map)
  225. }
  226. return nil
  227. }
  228. func walkPrimitive(v reflect.Value, w interface{}) error {
  229. if pw, ok := w.(PrimitiveWalker); ok {
  230. return pw.Primitive(v)
  231. }
  232. return nil
  233. }
  234. func walkSlice(v reflect.Value, w interface{}) (err error) {
  235. ew, ok := w.(EnterExitWalker)
  236. if ok {
  237. ew.Enter(Slice)
  238. }
  239. if sw, ok := w.(SliceWalker); ok {
  240. if err := sw.Slice(v); err != nil {
  241. return err
  242. }
  243. }
  244. for i := 0; i < v.Len(); i++ {
  245. elem := v.Index(i)
  246. if sw, ok := w.(SliceWalker); ok {
  247. if err := sw.SliceElem(i, elem); err != nil {
  248. return err
  249. }
  250. }
  251. ew, ok := w.(EnterExitWalker)
  252. if ok {
  253. ew.Enter(SliceElem)
  254. }
  255. if err := walk(elem, w); err != nil {
  256. return err
  257. }
  258. if ok {
  259. ew.Exit(SliceElem)
  260. }
  261. }
  262. ew, ok = w.(EnterExitWalker)
  263. if ok {
  264. ew.Exit(Slice)
  265. }
  266. return nil
  267. }
  268. func walkArray(v reflect.Value, w interface{}) (err error) {
  269. ew, ok := w.(EnterExitWalker)
  270. if ok {
  271. ew.Enter(Array)
  272. }
  273. if aw, ok := w.(ArrayWalker); ok {
  274. if err := aw.Array(v); err != nil {
  275. return err
  276. }
  277. }
  278. for i := 0; i < v.Len(); i++ {
  279. elem := v.Index(i)
  280. if aw, ok := w.(ArrayWalker); ok {
  281. if err := aw.ArrayElem(i, elem); err != nil {
  282. return err
  283. }
  284. }
  285. ew, ok := w.(EnterExitWalker)
  286. if ok {
  287. ew.Enter(ArrayElem)
  288. }
  289. if err := walk(elem, w); err != nil {
  290. return err
  291. }
  292. if ok {
  293. ew.Exit(ArrayElem)
  294. }
  295. }
  296. ew, ok = w.(EnterExitWalker)
  297. if ok {
  298. ew.Exit(Array)
  299. }
  300. return nil
  301. }
  302. func walkStruct(v reflect.Value, w interface{}) (err error) {
  303. ew, ewok := w.(EnterExitWalker)
  304. if ewok {
  305. ew.Enter(Struct)
  306. }
  307. skip := false
  308. if sw, ok := w.(StructWalker); ok {
  309. err = sw.Struct(v)
  310. if err == SkipEntry {
  311. skip = true
  312. err = nil
  313. }
  314. if err != nil {
  315. return
  316. }
  317. }
  318. if !skip {
  319. vt := v.Type()
  320. for i := 0; i < vt.NumField(); i++ {
  321. sf := vt.Field(i)
  322. f := v.FieldByIndex([]int{i})
  323. if sw, ok := w.(StructWalker); ok {
  324. err = sw.StructField(sf, f)
  325. // SkipEntry just pretends this field doesn't even exist
  326. if err == SkipEntry {
  327. continue
  328. }
  329. if err != nil {
  330. return
  331. }
  332. }
  333. ew, ok := w.(EnterExitWalker)
  334. if ok {
  335. ew.Enter(StructField)
  336. }
  337. err = walk(f, w)
  338. if err != nil {
  339. return
  340. }
  341. if ok {
  342. ew.Exit(StructField)
  343. }
  344. }
  345. }
  346. if ewok {
  347. ew.Exit(Struct)
  348. }
  349. return nil
  350. }