1package funk
2
3import (
4	"fmt"
5	"reflect"
6)
7
8func equal(expectedOrPredicate interface{}, optionalIsMap ...bool) func(keyValueIfMap, actualValue reflect.Value) bool {
9	isMap := append(optionalIsMap, false)[0]
10
11	if IsFunction(expectedOrPredicate) {
12		inTypes := []reflect.Type{nil}; if isMap {
13			inTypes = append(inTypes, nil)
14		}
15
16		if !IsPredicate(expectedOrPredicate, inTypes...) {
17			panic(fmt.Sprintf("Predicate function must have %d parameter and must return boolean", len(inTypes)))
18		}
19
20		predicateValue := reflect.ValueOf(expectedOrPredicate)
21
22		return func(keyValueIfMap, actualValue reflect.Value) bool {
23
24			if isMap && !keyValueIfMap.Type().ConvertibleTo(predicateValue.Type().In(0)) {
25				panic("Given key is not compatible with type of parameter for the predicate.")
26			}
27
28			if (isMap && !actualValue.Type().ConvertibleTo(predicateValue.Type().In(1))) ||
29				(!isMap && !actualValue.Type().ConvertibleTo(predicateValue.Type().In(0))) {
30				panic("Given value is not compatible with type of parameter for the predicate.")
31			}
32
33			args := []reflect.Value{actualValue}
34			if isMap {
35				args = append([]reflect.Value{keyValueIfMap}, args...)
36			}
37
38			return predicateValue.Call(args)[0].Bool()
39		}
40	}
41
42	expected := expectedOrPredicate
43
44	return func(keyValueIfMap, actualValue reflect.Value) bool {
45		if isMap {
46			actualValue = keyValueIfMap
47		}
48
49		if expected == nil || actualValue.IsZero() {
50			return actualValue.Interface() == expected
51		}
52
53		return reflect.DeepEqual(actualValue.Interface(), expected)
54	}
55}
56
57func sliceElem(rtype reflect.Type) reflect.Type {
58	for {
59		if rtype.Kind() != reflect.Slice && rtype.Kind() != reflect.Array {
60			return rtype
61		}
62
63		rtype = rtype.Elem()
64	}
65}
66
67func redirectValue(value reflect.Value) reflect.Value {
68	for {
69		if !value.IsValid() || (value.Kind() != reflect.Ptr && value.Kind() != reflect.Interface) {
70			return value
71		}
72
73		res := value.Elem()
74
75		// Test for a circular type.
76		if res.Kind() == reflect.Ptr && value.Kind() == reflect.Ptr && value.Pointer() == res.Pointer() {
77			return value
78		}
79
80		if !res.IsValid() && value.Kind() == reflect.Ptr {
81			return reflect.Zero(value.Type().Elem())
82		}
83
84		value = res
85	}
86}
87
88func makeSlice(value reflect.Value, values ...int) reflect.Value {
89	sliceType := sliceElem(value.Type())
90
91	size := value.Len()
92	cap := size
93
94	if len(values) > 0 {
95		size = values[0]
96	}
97
98	if len(values) > 1 {
99		cap = values[1]
100	}
101
102	return reflect.MakeSlice(reflect.SliceOf(sliceType), size, cap)
103}
104