extractFields returns a list of fields that JSON should recognize for the given type. The algorithm is breadth-first search over the set of structs to include - the top struct and then any reachable anonymous structs.
(obj interface{})
| 128 | // The algorithm is breadth-first search over the set of structs to include - the top struct |
| 129 | // and then any reachable anonymous structs. |
| 130 | func extractFields(obj interface{}) []*StructField { |
| 131 | t := reflect.TypeOf(obj) |
| 132 | // Anonymous fields to explore at the current level and the next. |
| 133 | current := []StructField{} |
| 134 | next := []StructField{{Typ: t}} |
| 135 | |
| 136 | // Count of queued names for current level and the next. |
| 137 | count := map[reflect.Type]int{} |
| 138 | nextCount := map[reflect.Type]int{} |
| 139 | |
| 140 | // Types already visited at an earlier level. |
| 141 | visited := map[reflect.Type]bool{} |
| 142 | |
| 143 | // Fields found. |
| 144 | var fields []*StructField |
| 145 | |
| 146 | for len(next) > 0 { |
| 147 | current, next = next, current[:0] |
| 148 | count, nextCount = nextCount, map[reflect.Type]int{} |
| 149 | |
| 150 | for _, f := range current { |
| 151 | if visited[f.Typ] { |
| 152 | continue |
| 153 | } |
| 154 | visited[f.Typ] = true |
| 155 | |
| 156 | // Scan f.typ for fields to include. |
| 157 | for i := 0; i < f.Typ.NumField(); i++ { |
| 158 | sf := f.Typ.Field(i) |
| 159 | if sf.PkgPath != "" { // unexported |
| 160 | continue |
| 161 | } |
| 162 | tag := sf.Tag.Get("json") |
| 163 | if tag == "-" { |
| 164 | continue |
| 165 | } |
| 166 | name, opts := parseTag(tag) |
| 167 | if !isValidTag(name) { |
| 168 | name = "" |
| 169 | } |
| 170 | |
| 171 | ft := sf.Type |
| 172 | ptr := false |
| 173 | if ft.Kind() == reflect.Ptr { |
| 174 | ptr = true |
| 175 | } |
| 176 | |
| 177 | if ft.Name() == "" && ft.Kind() == reflect.Ptr { |
| 178 | // Follow pointer. |
| 179 | ft = ft.Elem() |
| 180 | } |
| 181 | |
| 182 | // Record found field and index sequence. |
| 183 | if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { |
| 184 | tagged := name != "" |
| 185 | if name == "" { |
| 186 | name = sf.Name |
| 187 | } |
no test coverage detected
searching dependent graphs…