func makeResolveNonEmptyValue()

in gotype/fold_reflect.go [339:415]


func makeResolveNonEmptyValue(st reflect.Type) func(reflect.Value) (reflect.Value, bool) {
	type resolver func(reflect.Value) (reflect.Value, bool)

	resolveBySize := func(v reflect.Value) (reflect.Value, bool) {
		return v, v.Len() > 0
	}

	resolveIsZeroer := func(v reflect.Value) (reflect.Value, bool) {
		empty := v.Interface().(IsZeroer).IsZero()
		return v, !empty
	}

	resolveIsZeroerPtr := func(v reflect.Value) (reflect.Value, bool) {
		if v.CanAddr() {
			return resolveIsZeroer(v.Addr())
		}

		tmp := reflect.New(v.Type())
		tmp.Elem().Set(v)
		return resolveIsZeroer(tmp)
	}

	resolveInterfaceLazy := func(v reflect.Value) (reflect.Value, bool) {
		if v.IsNil() {
			return v, false
		}

		// Find potential resolver based on interface element type.
		// If no resolver is found, the value seems to be ok and should be reported.
		elem := v.Elem()
		resolver := makeResolveNonEmptyValue(elem.Type())
		if resolver == nil {
			return v, true // report, as v does not seem special
		}

		return resolver(v.Elem())
	}

	var resolvers []resolver
	for {
		switch st.Kind() {
		case reflect.Ptr:
			var r resolver
			st, r = makeResolvePointers(st)
			resolvers = append(resolvers, r)
			continue
		case reflect.Interface:
			resolvers = append(resolvers, resolveInterfaceLazy)
		case reflect.Map, reflect.String, reflect.Slice, reflect.Array:
			resolvers = append(resolvers, resolveBySize)
		default:
			if implementsIsZeroer(st) {
				resolvers = append(resolvers, resolveIsZeroer)
			} else if implementsPtrIsZeroer(st) {
				resolvers = append(resolvers, resolveIsZeroerPtr)
			}
		}
		break
	}

	if len(resolvers) == 0 {
		return nil
	}
	if len(resolvers) == 1 {
		return resolvers[0]
	}

	return func(v reflect.Value) (reflect.Value, bool) {
		for _, r := range resolvers {
			var ok bool
			if v, ok = r(v); !ok {
				return v, ok
			}
		}
		return v, true
	}
}