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

walker.go 4.5 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package serder
  2. import (
  3. "reflect"
  4. "github.com/zyedidia/generic/stack"
  5. )
  6. type WalkEvent interface{}
  7. type StructBeginEvent struct {
  8. Value reflect.Value
  9. }
  10. type StructArriveFieldEvent struct {
  11. Info reflect.StructField
  12. Value reflect.Value
  13. }
  14. type StructLeaveFieldEvent struct {
  15. Info reflect.StructField
  16. Value reflect.Value
  17. }
  18. type StructEndEvent struct {
  19. Value reflect.Value
  20. }
  21. type ArrayBeginEvent struct {
  22. Value reflect.Value
  23. }
  24. type ArrayArriveElementEvent struct {
  25. Index int
  26. Value reflect.Value
  27. }
  28. type ArrayLeaveElementEvent struct {
  29. Index int
  30. Value reflect.Value
  31. }
  32. type ArrayEndEvent struct {
  33. Value reflect.Value
  34. }
  35. type MapBeginEvent struct {
  36. Value reflect.Value
  37. }
  38. type MapArriveEntryEvent struct {
  39. Key reflect.Value
  40. Value reflect.Value
  41. }
  42. type MapLeaveEntryEvent struct {
  43. Key reflect.Value
  44. Value reflect.Value
  45. }
  46. type MapEndEvent struct {
  47. Value reflect.Value
  48. }
  49. type WalkingOp int
  50. const (
  51. Next WalkingOp = iota
  52. Skip
  53. Stop
  54. )
  55. type Walker func(ctx *WalkContext, event WalkEvent) WalkingOp
  56. type WalkContext struct {
  57. stack *stack.Stack[any]
  58. }
  59. func (c *WalkContext) StackPush(val any) {
  60. c.stack.Push(val)
  61. }
  62. func (c *WalkContext) StackPop() any {
  63. return c.stack.Pop()
  64. }
  65. func (c *WalkContext) StackPeek() any {
  66. return c.stack.Peek()
  67. }
  68. type WalkOption struct {
  69. StackValues []any
  70. }
  71. func WalkValue(value any, walker Walker, opts ...WalkOption) *WalkContext {
  72. var opt WalkOption
  73. if len(opts) > 0 {
  74. opt = opts[0]
  75. }
  76. ctx := &WalkContext{
  77. stack: stack.New[any](),
  78. }
  79. for _, v := range opt.StackValues {
  80. ctx.StackPush(v)
  81. }
  82. doWalking(ctx, reflect.ValueOf(value), walker)
  83. return ctx
  84. }
  85. func doWalking(ctx *WalkContext, val reflect.Value, walker Walker) WalkingOp {
  86. if !WillWalkInto(val) {
  87. return Next
  88. }
  89. switch val.Kind() {
  90. case reflect.Array:
  91. fallthrough
  92. case reflect.Slice:
  93. if walker(ctx, ArrayBeginEvent{Value: val}) == Stop {
  94. return Stop
  95. }
  96. for i := 0; i < val.Len(); i++ {
  97. eleVal := val.Index(i)
  98. op := walker(ctx, ArrayArriveElementEvent{
  99. Index: i,
  100. Value: eleVal,
  101. })
  102. if op == Skip {
  103. if walker(ctx, ArrayLeaveElementEvent{
  104. Index: i,
  105. Value: eleVal,
  106. }) == Stop {
  107. return Stop
  108. }
  109. continue
  110. }
  111. if op == Stop {
  112. return Stop
  113. }
  114. if doWalking(ctx, eleVal, walker) == Stop {
  115. return Stop
  116. }
  117. if walker(ctx, ArrayLeaveElementEvent{
  118. Index: i,
  119. Value: eleVal,
  120. }) == Stop {
  121. return Stop
  122. }
  123. }
  124. if walker(ctx, ArrayEndEvent{Value: val}) == Stop {
  125. return Stop
  126. }
  127. case reflect.Map:
  128. if walker(ctx, MapBeginEvent{Value: val}) == Stop {
  129. return Stop
  130. }
  131. keys := val.MapKeys()
  132. for _, key := range keys {
  133. val := val.MapIndex(key)
  134. op := walker(ctx, MapArriveEntryEvent{
  135. Key: key,
  136. Value: val,
  137. })
  138. if op == Skip {
  139. if walker(ctx, MapLeaveEntryEvent{
  140. Key: key,
  141. Value: val,
  142. }) == Stop {
  143. return Stop
  144. }
  145. continue
  146. }
  147. if op == Stop {
  148. return Stop
  149. }
  150. if doWalking(ctx, val, walker) == Stop {
  151. return Stop
  152. }
  153. if walker(ctx, MapLeaveEntryEvent{
  154. Key: key,
  155. Value: val,
  156. }) == Stop {
  157. return Stop
  158. }
  159. }
  160. if walker(ctx, MapEndEvent{Value: val}) == Stop {
  161. return Stop
  162. }
  163. case reflect.Struct:
  164. if walker(ctx, StructBeginEvent{Value: val}) == Stop {
  165. return Stop
  166. }
  167. for i := 0; i < val.NumField(); i++ {
  168. field := val.Field(i)
  169. op := walker(ctx, StructArriveFieldEvent{
  170. Info: val.Type().Field(i),
  171. Value: field,
  172. })
  173. if op == Skip {
  174. if walker(ctx, StructLeaveFieldEvent{
  175. Info: val.Type().Field(i),
  176. Value: field,
  177. }) == Stop {
  178. return Stop
  179. }
  180. continue
  181. }
  182. if op == Stop {
  183. return Stop
  184. }
  185. if doWalking(ctx, field, walker) == Stop {
  186. return Stop
  187. }
  188. if walker(ctx, StructLeaveFieldEvent{
  189. Info: val.Type().Field(i),
  190. Value: field,
  191. }) == Stop {
  192. return Stop
  193. }
  194. }
  195. if walker(ctx, StructEndEvent{Value: val}) == Stop {
  196. return Stop
  197. }
  198. case reflect.Interface:
  199. fallthrough
  200. case reflect.Pointer:
  201. eleVal := val.Elem()
  202. return doWalking(ctx, eleVal, walker)
  203. }
  204. return Next
  205. }
  206. const (
  207. WillWalkIntoTypeKinds = (1 << reflect.Array) | (1 << reflect.Map) | (1 << reflect.Slice) | (1 << reflect.Struct)
  208. )
  209. func WillWalkInto(val reflect.Value) bool {
  210. if val.IsZero() {
  211. return false
  212. }
  213. typ := val.Type()
  214. typeKind := typ.Kind()
  215. if typeKind == reflect.Interface || typeKind == reflect.Pointer {
  216. return WillWalkInto(val.Elem())
  217. }
  218. return ((1 << typeKind) & WillWalkIntoTypeKinds) != 0
  219. }

公共库

Contributors (1)