summaryrefslogtreecommitdiff
path: root/coll
diff options
context:
space:
mode:
authorDave Henderson <dhenderson@gmail.com>2025-03-09 20:14:46 -0400
committerGitHub <noreply@github.com>2025-03-10 00:14:46 +0000
commitbfa6b9dcef7592e6dd8225aaa0d0ab5aef5b3f84 (patch)
tree7e844defee92dc3af320df20baa6f9b421d4a4c9 /coll
parent7942441e61471f578a57910b3aa93636f5a0310d (diff)
chore(refactoring): Refactor/modernizations (#2345)
chore(refactoring): Refactor with modernization refactorings * range over int * replace interface{} with any * replace common map operations with maps.Copy/maps.Clone * simplifying loops with slices.Contains/ContainsFunc * modernize benchmarks with b.Loop * modernize tests with t.Context * use fmt.Appendf * range over strings.SplitSeq * use new stdlib crypto/pbkdf2 package --------- Signed-off-by: Dave Henderson <dhenderson@gmail.com>
Diffstat (limited to 'coll')
-rw-r--r--coll/coll.go100
-rw-r--r--coll/coll_test.go326
-rw-r--r--coll/index.go2
-rw-r--r--coll/index_test.go12
-rw-r--r--coll/jq.go18
-rw-r--r--coll/jq_test.go56
-rw-r--r--coll/jsonpath.go8
-rw-r--r--coll/jsonpath_test.go6
8 files changed, 256 insertions, 272 deletions
diff --git a/coll/coll.go b/coll/coll.go
index cbc96023..310e7cf3 100644
--- a/coll/coll.go
+++ b/coll/coll.go
@@ -1,13 +1,15 @@
// Package coll contains functions to help manipulate and query collections of
// data, like slices/arrays and maps.
//
-// For the functions that return an array, a []interface{} is returned,
+// For the functions that return an array, a []any is returned,
// regardless of whether or not the input was a different type.
package coll
import (
"fmt"
+ "maps"
"reflect"
+ "slices"
"sort"
"github.com/hairyhenderson/gomplate/v4/conv"
@@ -15,12 +17,12 @@ import (
)
// Slice creates a slice from a bunch of arguments
-func Slice(args ...interface{}) []interface{} {
+func Slice(args ...any) []any {
return args
}
// Has determines whether or not a given object has a property with the given key
-func Has(in interface{}, key interface{}) bool {
+func Has(in any, key any) bool {
av := reflect.ValueOf(in)
switch av.Kind() {
@@ -29,7 +31,7 @@ func Has(in interface{}, key interface{}) bool {
return av.MapIndex(kv).IsValid()
case reflect.Slice, reflect.Array:
l := av.Len()
- for i := 0; i < l; i++ {
+ for i := range l {
v := av.Index(i).Interface()
if reflect.DeepEqual(v, key) {
return true
@@ -45,8 +47,8 @@ func Has(in interface{}, key interface{}) bool {
// is provided, the last is used as the key, and an empty string is
// set as the value.
// All keys are converted to strings, regardless of input type.
-func Dict(v ...interface{}) (map[string]interface{}, error) {
- dict := map[string]interface{}{}
+func Dict(v ...any) (map[string]any, error) {
+ dict := map[string]any{}
lenv := len(v)
for i := 0; i < lenv; i += 2 {
key := conv.ToString(v[i])
@@ -61,7 +63,7 @@ func Dict(v ...interface{}) (map[string]interface{}, error) {
// Keys returns the list of keys in one or more maps. The returned list of keys
// is ordered by map, each in sorted key order.
-func Keys(in ...map[string]interface{}) ([]string, error) {
+func Keys(in ...map[string]any) ([]string, error) {
if len(in) == 0 {
return nil, fmt.Errorf("need at least one argument")
}
@@ -73,9 +75,9 @@ func Keys(in ...map[string]interface{}) ([]string, error) {
return keys, nil
}
-func splitMap(m map[string]interface{}) ([]string, []interface{}) {
+func splitMap(m map[string]any) ([]string, []any) {
keys := make([]string, len(m))
- values := make([]interface{}, len(m))
+ values := make([]any, len(m))
i := 0
for k := range m {
keys[i] = k
@@ -91,11 +93,11 @@ func splitMap(m map[string]interface{}) ([]string, []interface{}) {
// Values returns the list of values in one or more maps. The returned list of values
// is ordered by map, each in sorted key order. If the Keys function is called with
// the same arguments, the key/value mappings will be maintained.
-func Values(in ...map[string]interface{}) ([]interface{}, error) {
+func Values(in ...map[string]any) ([]any, error) {
if len(in) == 0 {
return nil, fmt.Errorf("need at least one argument")
}
- values := []interface{}{}
+ values := []any{}
for _, m := range in {
_, v := splitMap(m)
values = append(values, v...)
@@ -103,8 +105,8 @@ func Values(in ...map[string]interface{}) ([]interface{}, error) {
return values, nil
}
-// Append v to the end of list. No matter what type of input slice or array list is, a new []interface{} is always returned.
-func Append(v interface{}, list interface{}) ([]interface{}, error) {
+// Append v to the end of list. No matter what type of input slice or array list is, a new []any is always returned.
+func Append(v any, list any) ([]any, error) {
l, err := iconv.InterfaceSlice(list)
if err != nil {
return nil, err
@@ -113,24 +115,24 @@ func Append(v interface{}, list interface{}) ([]interface{}, error) {
return append(l, v), nil
}
-// Prepend v to the beginning of list. No matter what type of input slice or array list is, a new []interface{} is always returned.
-func Prepend(v interface{}, list interface{}) ([]interface{}, error) {
+// Prepend v to the beginning of list. No matter what type of input slice or array list is, a new []any is always returned.
+func Prepend(v any, list any) ([]any, error) {
l, err := iconv.InterfaceSlice(list)
if err != nil {
return nil, err
}
- return append([]interface{}{v}, l...), nil
+ return append([]any{v}, l...), nil
}
-// Uniq finds the unique values within list. No matter what type of input slice or array list is, a new []interface{} is always returned.
-func Uniq(list interface{}) ([]interface{}, error) {
+// Uniq finds the unique values within list. No matter what type of input slice or array list is, a new []any is always returned.
+func Uniq(list any) ([]any, error) {
l, err := iconv.InterfaceSlice(list)
if err != nil {
return nil, err
}
- out := []interface{}{}
+ out := []any{}
for _, v := range l {
if !Has(out, v) {
out = append(out, v)
@@ -139,8 +141,8 @@ func Uniq(list interface{}) ([]interface{}, error) {
return out, nil
}
-// Reverse the list. No matter what type of input slice or array list is, a new []interface{} is always returned.
-func Reverse(list interface{}) ([]interface{}, error) {
+// Reverse the list. No matter what type of input slice or array list is, a new []any is always returned.
+func Reverse(list any) ([]any, error) {
l, err := iconv.InterfaceSlice(list)
if err != nil {
return nil, err
@@ -155,29 +157,19 @@ func Reverse(list interface{}) ([]interface{}, error) {
// Merge source maps (srcs) into dst. Precedence is in left-to-right order, with
// the left-most values taking precedence over the right-most.
-func Merge(dst map[string]interface{}, srcs ...map[string]interface{}) (map[string]interface{}, error) {
+func Merge(dst map[string]any, srcs ...map[string]any) (map[string]any, error) {
for _, src := range srcs {
dst = mergeValues(src, dst)
}
return dst, nil
}
-// returns whether or not a contains v
-func contains(v string, a []string) bool {
- for _, n := range a {
- if n == v {
- return true
- }
- }
- return false
-}
-
// Omit returns a new map without any entries that have the
// given keys (inverse of Pick).
-func Omit(in map[string]interface{}, keys ...string) map[string]interface{} {
- out := map[string]interface{}{}
+func Omit(in map[string]any, keys ...string) map[string]any {
+ out := map[string]any{}
for k, v := range in {
- if !contains(k, keys) {
+ if !slices.Contains(keys, k) {
out[k] = v
}
}
@@ -186,42 +178,34 @@ func Omit(in map[string]interface{}, keys ...string) map[string]interface{} {
// Pick returns a new map with any entries that have the
// given keys (inverse of Omit).
-func Pick(in map[string]interface{}, keys ...string) map[string]interface{} {
- out := map[string]interface{}{}
+func Pick(in map[string]any, keys ...string) map[string]any {
+ out := map[string]any{}
for k, v := range in {
- if contains(k, keys) {
+ if slices.Contains(keys, k) {
out[k] = v
}
}
return out
}
-func copyMap(m map[string]interface{}) map[string]interface{} {
- n := map[string]interface{}{}
- for k, v := range m {
- n[k] = v
- }
- return n
-}
-
// Merges a default and override map
-func mergeValues(d map[string]interface{}, o map[string]interface{}) map[string]interface{} {
- def := copyMap(d)
- over := copyMap(o)
+func mergeValues(d map[string]any, o map[string]any) map[string]any {
+ def := maps.Clone(d)
+ over := maps.Clone(o)
for k, v := range over {
// If the key doesn't exist already, then just set the key to that value
if _, exists := def[k]; !exists {
def[k] = v
continue
}
- nextMap, ok := v.(map[string]interface{})
+ nextMap, ok := v.(map[string]any)
// If it isn't another map, overwrite the value
if !ok {
def[k] = v
continue
}
// Edge case: If the key exists in the default, but isn't a map
- defMap, isMap := def[k].(map[string]interface{})
+ defMap, isMap := def[k].(map[string]any)
// If the override map has a map for this key, prefer it
if !isMap {
def[k] = v
@@ -238,7 +222,7 @@ func mergeValues(d map[string]interface{}, o map[string]interface{}) map[string]
// sort by the values of those entries.
//
// Does not modify the input list.
-func Sort(key string, list interface{}) (out []interface{}, err error) {
+func Sort(key string, list any) (out []any, err error) {
if list == nil {
return nil, nil
}
@@ -249,7 +233,7 @@ func Sort(key string, list interface{}) (out []interface{}, err error) {
}
// if the types are all the same, we can sort the slice
if sameTypes(ia) {
- s := make([]interface{}, len(ia))
+ s := make([]any, len(ia))
// make a copy so the original is unmodified
copy(s, ia)
sort.SliceStable(s, func(i, j int) bool {
@@ -261,8 +245,8 @@ func Sort(key string, list interface{}) (out []interface{}, err error) {
}
// lessThan - compare two values of the same type
-func lessThan(key string) func(left, right interface{}) bool {
- return func(left, right interface{}) bool {
+func lessThan(key string) func(left, right any) bool {
+ return func(left, right any) bool {
val := reflect.Indirect(reflect.ValueOf(left))
rval := reflect.Indirect(reflect.ValueOf(right))
switch val.Kind() {
@@ -299,7 +283,7 @@ func lessThan(key string) func(left, right interface{}) bool {
}
}
-func sameTypes(a []interface{}) bool {
+func sameTypes(a []any) bool {
var t reflect.Type
for _, v := range a {
if t == nil {
@@ -315,7 +299,7 @@ func sameTypes(a []interface{}) bool {
// Flatten a nested array or slice to at most 'depth' levels. Use depth of -1
// to completely flatten the input.
// Returns a new slice without modifying the input.
-func Flatten(list interface{}, depth int) ([]interface{}, error) {
+func Flatten(list any, depth int) ([]any, error) {
l, err := iconv.InterfaceSlice(list)
if err != nil {
return nil, err
@@ -323,7 +307,7 @@ func Flatten(list interface{}, depth int) ([]interface{}, error) {
if depth == 0 {
return l, nil
}
- out := make([]interface{}, 0, len(l)*2)
+ out := make([]any, 0, len(l)*2)
for _, v := range l {
s := reflect.ValueOf(v)
kind := s.Kind()
diff --git a/coll/coll_test.go b/coll/coll_test.go
index 4f7da49f..ab2241ee 100644
--- a/coll/coll_test.go
+++ b/coll/coll_test.go
@@ -16,24 +16,24 @@ func TestSlice(t *testing.T) {
}
func TestHas(t *testing.T) {
- in := map[string]interface{}{
+ in := map[string]any{
"foo": "bar",
- "baz": map[string]interface{}{
+ "baz": map[string]any{
"qux": "quux",
},
}
testdata := []struct {
- in interface{}
- key interface{}
+ in any
+ key any
out bool
}{
{in, "foo", true},
{in, "bar", false},
{in["baz"], "qux", true},
{[]string{"foo", "bar", "baz"}, "bar", true},
- {[]interface{}{"foo", "bar", "baz"}, "bar", true},
- {[]interface{}{"foo", "bar", "baz"}, 42, false},
+ {[]any{"foo", "bar", "baz"}, "bar", true},
+ {[]any{"foo", "bar", "baz"}, 42, false},
{[]int{1, 2, 42}, 42, true},
}
@@ -44,16 +44,16 @@ func TestHas(t *testing.T) {
func TestDict(t *testing.T) {
testdata := []struct {
- expected map[string]interface{}
- args []interface{}
+ expected map[string]any
+ args []any
}{
- {expected: map[string]interface{}{}},
- {args: []interface{}{}, expected: map[string]interface{}{}},
- {args: []interface{}{"foo"}, expected: map[string]interface{}{"foo": ""}},
- {args: []interface{}{42}, expected: map[string]interface{}{"42": ""}},
- {args: []interface{}{"foo", nil}, expected: map[string]interface{}{"foo": nil}},
- {args: []interface{}{"foo", "bar"}, expected: map[string]interface{}{"foo": "bar"}},
- {args: []interface{}{"foo", "bar", "baz", true}, expected: map[string]interface{}{
+ {expected: map[string]any{}},
+ {args: []any{}, expected: map[string]any{}},
+ {args: []any{"foo"}, expected: map[string]any{"foo": ""}},
+ {args: []any{42}, expected: map[string]any{"42": ""}},
+ {args: []any{"foo", nil}, expected: map[string]any{"foo": nil}},
+ {args: []any{"foo", "bar"}, expected: map[string]any{"foo": "bar"}},
+ {args: []any{"foo", "bar", "baz", true}, expected: map[string]any{
"foo": "bar",
"baz": true,
}},
@@ -69,7 +69,7 @@ func TestKeys(t *testing.T) {
_, err := Keys()
require.Error(t, err)
- in := map[string]interface{}{
+ in := map[string]any{
"foo": 1,
"bar": 2,
}
@@ -78,7 +78,7 @@ func TestKeys(t *testing.T) {
require.NoError(t, err)
assert.EqualValues(t, expected, keys)
- in2 := map[string]interface{}{
+ in2 := map[string]any{
"baz": 3,
"qux": 4,
}
@@ -87,7 +87,7 @@ func TestKeys(t *testing.T) {
require.NoError(t, err)
assert.EqualValues(t, expected, keys)
- in3 := map[string]interface{}{
+ in3 := map[string]any{
"Foo": 5,
"Bar": 6,
"foo": 7,
@@ -103,114 +103,114 @@ func TestValues(t *testing.T) {
_, err := Values()
require.Error(t, err)
- in := map[string]interface{}{
+ in := map[string]any{
"foo": 1,
"bar": 2,
}
- expected := []interface{}{2, 1}
+ expected := []any{2, 1}
values, err := Values(in)
require.NoError(t, err)
assert.EqualValues(t, expected, values)
- in2 := map[string]interface{}{
+ in2 := map[string]any{
"baz": 3,
"qux": 4,
}
- expected = []interface{}{2, 1, 3, 4}
+ expected = []any{2, 1, 3, 4}
values, err = Values(in, in2)
require.NoError(t, err)
assert.EqualValues(t, expected, values)
- in3 := map[string]interface{}{
+ in3 := map[string]any{
"Foo": 5,
"Bar": 6,
"foo": 7,
"bar": 8,
}
- expected = []interface{}{2, 1, 3, 4, 6, 5, 8, 7}
+ expected = []any{2, 1, 3, 4, 6, 5, 8, 7}
values, err = Values(in, in2, in3)
require.NoError(t, err)
assert.EqualValues(t, expected, values)
}
func TestAppend(t *testing.T) {
- out, err := Append(42, []interface{}{})
+ out, err := Append(42, []any{})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{42}, out)
+ assert.EqualValues(t, []any{42}, out)
- out, err = Append(42, []interface{}{4.9, false, "foo"})
+ out, err = Append(42, []any{4.9, false, "foo"})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{4.9, false, "foo", 42}, out)
+ assert.EqualValues(t, []any{4.9, false, "foo", 42}, out)
- // a strange but valid use-cases, since we're converting to an []interface{}
+ // a strange but valid use-cases, since we're converting to an []any
out, err = Append(42, []string{"foo"})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{"foo", 42}, out)
+ assert.EqualValues(t, []any{"foo", 42}, out)
out, err = Append("baz", []string{"foo", "bar"})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{"foo", "bar", "baz"}, out)
+ assert.EqualValues(t, []any{"foo", "bar", "baz"}, out)
}
func TestPrepend(t *testing.T) {
- out, err := Prepend(42, []interface{}{})
+ out, err := Prepend(42, []any{})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{42}, out)
+ assert.EqualValues(t, []any{42}, out)
- out, err = Prepend(42, []interface{}{4.9, false, "foo"})
+ out, err = Prepend(42, []any{4.9, false, "foo"})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{42, 4.9, false, "foo"}, out)
+ assert.EqualValues(t, []any{42, 4.9, false, "foo"}, out)
- // a strange but valid use-cases, since we're converting to an []interface{}
+ // a strange but valid use-cases, since we're converting to an []any
out, err = Prepend(42, []string{"foo"})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{42, "foo"}, out)
+ assert.EqualValues(t, []any{42, "foo"}, out)
out, err = Prepend("foo", []string{"bar", "baz"})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{"foo", "bar", "baz"}, out)
+ assert.EqualValues(t, []any{"foo", "bar", "baz"}, out)
}
func TestUniq(t *testing.T) {
- out, err := Uniq([]interface{}{1, 2, 3, 1, true, false, true, "1", 2})
+ out, err := Uniq([]any{1, 2, 3, 1, true, false, true, "1", 2})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{1, 2, 3, true, false, "1"}, out)
+ assert.EqualValues(t, []any{1, 2, 3, true, false, "1"}, out)
out, err = Uniq([]string{"one", "two", "one", "three"})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{"one", "two", "three"}, out)
+ assert.EqualValues(t, []any{"one", "two", "three"}, out)
}
func TestReverse(t *testing.T) {
- out, err := Reverse([]interface{}{})
+ out, err := Reverse([]any{})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{}, out)
+ assert.EqualValues(t, []any{}, out)
- out, err = Reverse([]interface{}{8})
+ out, err = Reverse([]any{8})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{8}, out)
+ assert.EqualValues(t, []any{8}, out)
- out, err = Reverse([]interface{}{1, 2, 3, 4})
+ out, err = Reverse([]any{1, 2, 3, 4})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{4, 3, 2, 1}, out)
+ assert.EqualValues(t, []any{4, 3, 2, 1}, out)
out, err = Reverse([]int{1, 2, 3, 4})
require.NoError(t, err)
- assert.EqualValues(t, []interface{}{4, 3, 2, 1}, out)
+ assert.EqualValues(t, []any{4, 3, 2, 1}, out)
}
func TestMerge(t *testing.T) {
- dst := map[string]interface{}{}
- src := map[string]interface{}{}
- expected := map[string]interface{}{}
+ dst := map[string]any{}
+ src := map[string]any{}
+ expected := map[string]any{}
out, err := Merge(dst, src)
require.NoError(t, err)
assert.EqualValues(t, expected, out)
- dst = map[string]interface{}{"a": 4, "c": 5}
- src = map[string]interface{}{"a": 1, "b": 2, "c": 3}
- expected = map[string]interface{}{
+ dst = map[string]any{"a": 4, "c": 5}
+ src = map[string]any{"a": 1, "b": 2, "c": 3}
+ expected = map[string]any{
"a": dst["a"], "b": src["b"], "c": dst["c"],
}
@@ -218,10 +218,10 @@ func TestMerge(t *testing.T) {
require.NoError(t, err)
assert.EqualValues(t, expected, out)
- dst = map[string]interface{}{"a": 4, "c": 5}
- src = map[string]interface{}{"a": 1, "b": 2, "c": 3}
- src2 := map[string]interface{}{"a": 1, "b": 2, "c": 3, "d": 4}
- expected = map[string]interface{}{
+ dst = map[string]any{"a": 4, "c": 5}
+ src = map[string]any{"a": 1, "b": 2, "c": 3}
+ src2 := map[string]any{"a": 1, "b": 2, "c": 3, "d": 4}
+ expected = map[string]any{
"a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"],
}
@@ -229,10 +229,10 @@ func TestMerge(t *testing.T) {
require.NoError(t, err)
assert.EqualValues(t, expected, out)
- dst = map[string]interface{}{"a": false, "c": 5}
- src = map[string]interface{}{"a": true, "b": 2, "c": 3}
- src2 = map[string]interface{}{"a": true, "b": 2, "c": 3, "d": 4}
- expected = map[string]interface{}{
+ dst = map[string]any{"a": false, "c": 5}
+ src = map[string]any{"a": true, "b": 2, "c": 3}
+ src2 = map[string]any{"a": true, "b": 2, "c": 3, "d": 4}
+ expected = map[string]any{
"a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"],
}
@@ -240,15 +240,15 @@ func TestMerge(t *testing.T) {
require.NoError(t, err)
assert.EqualValues(t, expected, out)
- dst = map[string]interface{}{"a": true, "c": 5}
- src = map[string]interface{}{
+ dst = map[string]any{"a": true, "c": 5}
+ src = map[string]any{
"a": false,
- "b": map[string]interface{}{
+ "b": map[string]any{
"ca": "foo",
},
}
- src2 = map[string]interface{}{"a": false, "b": 2, "c": 3, "d": 4}
- expected = map[string]interface{}{
+ src2 = map[string]any{"a": false, "b": 2, "c": 3, "d": 4}
+ expected = map[string]any{
"a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"],
}
@@ -256,22 +256,22 @@ func TestMerge(t *testing.T) {
require.NoError(t, err)
assert.EqualValues(t, expected, out)
- dst = map[string]interface{}{
+ dst = map[string]any{
"a": true,
- "b": map[string]interface{}{
+ "b": map[string]any{
"ca": "foo",
"cb": "bar",
},
"c": 5,
}
- src = map[string]interface{}{
+ src = map[string]any{
"a": false,
- "b": map[string]interface{}{
+ "b": map[string]any{
"ca": 8,
},
}
- expected = map[string]interface{}{
- "a": dst["a"], "b": map[string]interface{}{
+ expected = map[string]any{
+ "a": dst["a"], "b": map[string]any{
"ca": "foo",
"cb": "bar",
}, "c": dst["c"],
@@ -288,19 +288,19 @@ type coords struct {
func TestSameTypes(t *testing.T) {
data := []struct {
- in []interface{}
+ in []any
out bool
}{
- {[]interface{}{}, true},
- {[]interface{}{"a", "b"}, true},
- {[]interface{}{1.0, 3.14}, true},
- {[]interface{}{1, 3}, true},
- {[]interface{}{true, false}, true},
- {[]interface{}{1, 3.0}, false},
- {[]interface{}{"a", nil}, false},
- {[]interface{}{"a", true}, false},
- {[]interface{}{coords{2, 3}, coords{3, 4}}, true},
- {[]interface{}{coords{2, 3}, &coords{3, 4}}, false},
+ {[]any{}, true},
+ {[]any{"a", "b"}, true},
+ {[]any{1.0, 3.14}, true},
+ {[]any{1, 3}, true},
+ {[]any{true, false}, true},
+ {[]any{1, 3.0}, false},
+ {[]any{"a", nil}, false},
+ {[]any{"a", true}, false},
+ {[]any{coords{2, 3}, coords{3, 4}}, true},
+ {[]any{coords{2, 3}, &coords{3, 4}}, false},
}
for _, d := range data {
@@ -310,7 +310,7 @@ func TestSameTypes(t *testing.T) {
func TestLessThan(t *testing.T) {
data := []struct {
- left, right interface{}
+ left, right any
key string
out bool
}{
@@ -324,17 +324,17 @@ func TestLessThan(t *testing.T) {
{left: uint(0xff), right: uint(0x32)},
{left: 1, right: 3, out: true},
{left: true, right: false, out: false},
- {left: map[string]interface{}{"foo": 1}, right: map[string]interface{}{"foo": 2}},
+ {left: map[string]any{"foo": 1}, right: map[string]any{"foo": 2}},
{
key: "foo",
- left: map[string]interface{}{"foo": 1},
- right: map[string]interface{}{"foo": 2},
+ left: map[string]any{"foo": 1},
+ right: map[string]any{"foo": 2},
out: true,
},
{
key: "bar",
- left: map[string]interface{}{"foo": 1},
- right: map[string]interface{}{"foo": 2},
+ left: map[string]any{"foo": 1},
+ right: map[string]any{"foo": 2},
},
{key: "X", left: coords{}, right: coords{-1, 2}},
{key: "Y", left: &coords{1, 1}, right: &coords{-1, 2}, out: true},
@@ -356,23 +356,23 @@ func TestSort(t *testing.T) {
data := []struct {
key string
- in interface{}
- out []interface{}
+ in any
+ out []any
}{
{
key: "",
in: []string{"b", "c", "a", "d"},
- out: []interface{}{"a", "b", "c", "d"},
+ out: []any{"a", "b", "c", "d"},
},
{
key: "",
- in: []interface{}{"b", "c", "a", "d"},
- out: []interface{}{"a", "b", "c", "d"},
+ in: []any{"b", "c", "a", "d"},
+ out: []any{"a", "b", "c", "d"},
},
{
key: "",
- in: []interface{}{"c", "a", "b", 3, 1, 2},
- out: []interface{}{"c", "a", "b", 3, 1, 2},
+ in: []any{"c", "a", "b", 3, 1, 2},
+ out: []any{"c", "a", "b", 3, 1, 2},
},
{
key: "",
@@ -382,41 +382,41 @@ func TestSort(t *testing.T) {
{
key: "",
- in: []map[string]interface{}{
+ in: []map[string]any{
{"name": "Bart", "age": 12},
{"age": 1, "name": "Maggie"},
{"name": "Lisa", "age": 6},
},
- out: []interface{}{
- map[string]interface{}{"name": "Bart", "age": 12},
- map[string]interface{}{"age": 1, "name": "Maggie"},
- map[string]interface{}{"name": "Lisa", "age": 6},
+ out: []any{
+ map[string]any{"name": "Bart", "age": 12},
+ map[string]any{"age": 1, "name": "Maggie"},
+ map[string]any{"name": "Lisa", "age": 6},
},
},
{
key: "name",
- in: []map[string]interface{}{
+ in: []map[string]any{
{"name": "Bart", "age": 12},
{"age": 1, "name": "Maggie"},
{"name": "Lisa", "age": 6},
},
- out: []interface{}{
- map[string]interface{}{"name": "Bart", "age": 12},
- map[string]interface{}{"name": "Lisa", "age": 6},
- map[string]interface{}{"age": 1, "name": "Maggie"},
+ out: []any{
+ map[string]any{"name": "Bart", "age": 12},
+ map[string]any{"name": "Lisa", "age": 6},
+ map[string]any{"age": 1, "name": "Maggie"},
},
},
{
key: "age",
- in: []map[string]interface{}{
+ in: []map[string]any{
{"name": "Bart", "age": 12},
{"age": 1, "name": "Maggie"},
{"name": "Lisa", "age": 6},
},
- out: []interface{}{
- map[string]interface{}{"age": 1, "name": "Maggie"},
- map[string]interface{}{"name": "Lisa", "age": 6},
- map[string]interface{}{"name": "Bart", "age": 12},
+ out: []any{
+ map[string]any{"age": 1, "name": "Maggie"},
+ map[string]any{"name": "Lisa", "age": 6},
+ map[string]any{"name": "Bart", "age": 12},
},
},
{
@@ -426,7 +426,7 @@ func TestSort(t *testing.T) {
{"x": 13, "y": -8},
{"x": 1, "y": 0},
},
- out: []interface{}{
+ out: []any{
map[string]int{"x": 13, "y": -8},
map[string]int{"x": 1, "y": 0},
map[string]int{"x": 54, "y": 6},
@@ -439,7 +439,7 @@ func TestSort(t *testing.T) {
{3, 3},
{1, 5},
},
- out: []interface{}{
+ out: []any{
coords{1, 5},
coords{2, 4},
coords{3, 3},
@@ -452,7 +452,7 @@ func TestSort(t *testing.T) {
{3, 3},
{1, 5},
},
- out: []interface{}{
+ out: []any{
&coords{1, 5},
&coords{2, 4},
&coords{3, 3},
@@ -471,70 +471,70 @@ func TestSort(t *testing.T) {
func TestFlatten(t *testing.T) {
data := []struct {
- in interface{}
- expected []interface{}
+ in any
+ expected []any
depth int
}{
- {in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
- {in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
- {in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{[]string{}, []int{1, 2}, 3}},
+ {in: []int{1, 2, 3}, expected: []any{1, 2, 3}},
+ {in: [3]int{1, 2, 3}, expected: []any{1, 2, 3}},
+ {in: []any{[]string{}, []int{1, 2}, 3}, expected: []any{[]string{}, []int{1, 2}, 3}},
{
- in: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
- expected: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
+ in: []any{[]string{"one"}, [][]int{{1, 2}}, 3},
+ expected: []any{[]string{"one"}, [][]int{{1, 2}}, 3},
},
- {depth: 1, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
- {depth: 1, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
- {depth: 1, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}},
+ {depth: 1, in: []int{1, 2, 3}, expected: []any{1, 2, 3}},
+ {depth: 1, in: [3]int{1, 2, 3}, expected: []any{1, 2, 3}},
+ {depth: 1, in: []any{[]string{}, []int{1, 2}, 3}, expected: []any{1, 2, 3}},
{
depth: 1,
- in: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
- expected: []interface{}{"one", []int{1, 2}, 3},
+ in: []any{[]string{"one"}, [][]int{{1, 2}}, 3},
+ expected: []any{"one", []int{1, 2}, 3},
},
- {depth: 2, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
- {depth: 2, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
- {depth: 2, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}},
+ {depth: 2, in: []int{1, 2, 3}, expected: []any{1, 2, 3}},
+ {depth: 2, in: [3]int{1, 2, 3}, expected: []any{1, 2, 3}},
+ {depth: 2, in: []any{[]string{}, []int{1, 2}, 3}, expected: []any{1, 2, 3}},
{
depth: 2,
- in: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
- expected: []interface{}{"one", 1, 2, 3},
+ in: []any{[]string{"one"}, [][]int{{1, 2}}, 3},
+ expected: []any{"one", 1, 2, 3},
},
{
depth: 2,
- in: []interface{}{
+ in: []any{
[]string{"one"},
- []interface{}{
- []interface{}{
+ []any{
+ []any{
[]int{1},
- []interface{}{2, []int{3}},
+ []any{2, []int{3}},
},
[]int{4, 5},
},
6,
},
- expected: []interface{}{"one", []int{1}, []interface{}{2, []int{3}}, 4, 5, 6},
+ expected: []any{"one", []int{1}, []any{2, []int{3}}, 4, 5, 6},
},
- {depth: -1, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
- {depth: -1, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}},
- {depth: -1, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}},
+ {depth: -1, in: []int{1, 2, 3}, expected: []any{1, 2, 3}},
+ {depth: -1, in: [3]int{1, 2, 3}, expected: []any{1, 2, 3}},
+ {depth: -1, in: []any{[]string{}, []int{1, 2}, 3}, expected: []any{1, 2, 3}},
{
depth: -1,
- in: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
- expected: []interface{}{"one", 1, 2, 3},
+ in: []any{[]string{"one"}, [][]int{{1, 2}}, 3},
+ expected: []any{"one", 1, 2, 3},
},
{
depth: -1,
- in: []interface{}{
+ in: []any{
[]string{"one"},
- []interface{}{
- []interface{}{
+ []any{
+ []any{
[]int{1},
- []interface{}{2, []int{3}},
+ []any{2, []int{3}},
},
[]int{4, 5},
},
6,
},
- expected: []interface{}{"one", 1, 2, 3, 4, 5, 6},
+ expected: []any{"one", 1, 2, 3, 4, 5, 6},
},
}
@@ -549,17 +549,17 @@ func TestFlatten(t *testing.T) {
}
func BenchmarkFlatten(b *testing.B) {
- data := []interface{}{
+ data := []any{
[]int{1, 2, 3},
[3]int{1, 2, 3},
- []interface{}{[]string{}, []int{1, 2}, 3},
- []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3},
- []interface{}{
+ []any{[]string{}, []int{1, 2}, 3},
+ []any{[]string{"one"}, [][]int{{1, 2}}, 3},
+ []any{
[]string{"one"},
- []interface{}{
- []interface{}{
+ []any{
+ []any{
[]int{1},
- []interface{}{2, []int{3}},
+ []any{2, []int{3}},
},
[]int{4, 5},
},
@@ -569,7 +569,7 @@ func BenchmarkFlatten(b *testing.B) {
for depth := -1; depth <= 2; depth++ {
for _, d := range data {
b.Run(fmt.Sprintf("depth%d %T(%v)", depth, d, d), func(b *testing.B) {
- for i := 0; i < b.N; i++ {
+ for b.Loop() {
Flatten(d, depth)
}
})
@@ -578,42 +578,42 @@ func BenchmarkFlatten(b *testing.B) {
}
func TestOmit(t *testing.T) {
- in := map[string]interface{}{
+ in := map[string]any{
"foo": "bar",
"bar": true,
"": "baz",
}
assert.EqualValues(t, in, Omit(in, "baz"))
- expected := map[string]interface{}{
+ expected := map[string]any{
"foo": "bar",
"bar": true,
}
assert.EqualValues(t, expected, Omit(in, ""))
- expected = map[string]interface{}{
+ expected = map[string]any{
"": "baz",
}
assert.EqualValues(t, expected, Omit(in, "foo", "bar"))
- assert.EqualValues(t, map[string]interface{}{}, Omit(in, "foo", "bar", ""))
+ assert.EqualValues(t, map[string]any{}, Omit(in, "foo", "bar", ""))
}
func TestPick(t *testing.T) {
- in := map[string]interface{}{
+ in := map[string]any{
"foo": "bar",
"bar": true,
"": "baz",
}
- expected := map[string]interface{}{}
+ expected := map[string]any{}
assert.EqualValues(t, expected, Pick(in, "baz"))
- expected = map[string]interface{}{
+ expected = map[string]any{
"": "baz",
}
assert.EqualValues(t, expected, Pick(in, ""))
- expected = map[string]interface{}{
+ expected = map[string]any{
"foo": "bar",
"bar": true,
}
diff --git a/coll/index.go b/coll/index.go
index ba815320..46402a51 100644
--- a/coll/index.go
+++ b/coll/index.go
@@ -14,7 +14,7 @@ import (
// will return an error if the key is not found. Note that the argument order is
// different from the template function definition found in `funcs/coll.go` to
// allow for variadic indexes.
-func Index(v interface{}, keys ...interface{}) (interface{}, error) {
+func Index(v any, keys ...any) (any, error) {
item := reflect.ValueOf(v)
item = indirectInterface(item)
if !item.IsValid() {
diff --git a/coll/index_test.go b/coll/index_test.go
index 521e8cef..88993e93 100644
--- a/coll/index_test.go
+++ b/coll/index_test.go
@@ -8,28 +8,28 @@ import (
)
func TestIndex(t *testing.T) {
- out, err := Index(map[string]interface{}{
+ out, err := Index(map[string]any{
"foo": "bar", "baz": "qux",
}, "foo")
require.NoError(t, err)
assert.Equal(t, "bar", out)
- out, err = Index(map[string]interface{}{
+ out, err = Index(map[string]any{
"foo": "bar", "baz": "qux", "quux": "corge",
}, "foo", 2)
require.NoError(t, err)
assert.Equal(t, byte('r'), out)
- out, err = Index([]interface{}{"foo", "bar", "baz"}, 2)
+ out, err = Index([]any{"foo", "bar", "baz"}, 2)
require.NoError(t, err)
assert.Equal(t, "baz", out)
- out, err = Index([]interface{}{"foo", "bar", "baz"}, 2, 2)
+ out, err = Index([]any{"foo", "bar", "baz"}, 2, 2)
require.NoError(t, err)
assert.Equal(t, byte('z'), out)
// error cases
- out, err = Index([]interface{}{"foo", "bar", "baz"}, 0, 1, 2)
+ out, err = Index([]any{"foo", "bar", "baz"}, 0, 1, 2)
require.Error(t, err)
assert.Nil(t, out)
@@ -41,7 +41,7 @@ func TestIndex(t *testing.T) {
require.Error(t, err)
assert.Nil(t, out)
- out, err = Index(map[interface{}]string{nil: "foo", 2: "bar"}, "baz")
+ out, err = Index(map[any]string{nil: "foo", 2: "bar"}, "baz")
require.Error(t, err)
assert.Nil(t, out)
diff --git a/coll/jq.go b/coll/jq.go
index 16dc8f0e..fa7777ff 100644
--- a/coll/jq.go
+++ b/coll/jq.go
@@ -10,7 +10,7 @@ import (
)
// JQ -
-func JQ(ctx context.Context, jqExpr string, in interface{}) (interface{}, error) {
+func JQ(ctx context.Context, jqExpr string, in any) (any, error) {
query, err := gojq.Parse(jqExpr)
if err != nil {
return nil, fmt.Errorf("jq parsing expression %q: %w", jqExpr, err)
@@ -23,8 +23,8 @@ func JQ(ctx context.Context, jqExpr string, in interface{}) (interface{}, error)
}
iter := query.RunWithContext(ctx, in)
- var out interface{}
- a := []interface{}{}
+ var out any
+ a := []any{}
for {
v, ok := iter.Next()
if !ok {
@@ -44,12 +44,12 @@ func JQ(ctx context.Context, jqExpr string, in interface{}) (interface{}, error)
return out, nil
}
-// jqConvertType converts the input to a map[string]interface{}, []interface{},
+// jqConvertType converts the input to a map[string]any, []any,
// or other supported primitive JSON types.
-func jqConvertType(in interface{}) (interface{}, error) {
+func jqConvertType(in any) (any, error) {
// if it's already a supported type, pass it through
switch in.(type) {
- case map[string]interface{}, []interface{},
+ case map[string]any, []any,
string, []byte,
nil, bool,
int, int8, int16, int32, int64,
@@ -67,8 +67,8 @@ func jqConvertType(in interface{}) (interface{}, error) {
value = value.Elem()
}
- mapType := reflect.TypeOf(map[string]interface{}{})
- sliceType := reflect.TypeOf([]interface{}{})
+ mapType := reflect.TypeOf(map[string]any{})
+ sliceType := reflect.TypeOf([]any{})
// if it can be converted to a map or slice, do that
if inType.ConvertibleTo(mapType) {
return value.Convert(mapType).Interface(), nil
@@ -83,7 +83,7 @@ func jqConvertType(in interface{}) (interface{}, error) {
if err != nil {
return nil, fmt.Errorf("json marshal struct: %w", err)
}
- var m map[string]interface{}
+ var m map[string]any
err = json.Unmarshal(b, &m)
if err != nil {
return nil, fmt.Errorf("json unmarshal struct: %w", err)
diff --git a/coll/jq_test.go b/coll/jq_test.go
index e4af3847..0d45fdfb 100644
--- a/coll/jq_test.go
+++ b/coll/jq_test.go
@@ -11,29 +11,29 @@ import (
func TestJQ(t *testing.T) {
ctx := context.Background()
- in := map[string]interface{}{
- "store": map[string]interface{}{
- "book": []interface{}{
- map[string]interface{}{
+ in := map[string]any{
+ "store": map[string]any{
+ "book": []any{
+ map[string]any{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95,
},
- map[string]interface{}{
+ map[string]any{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99,
},
- map[string]interface{}{
+ map[string]any{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99,
},
- map[string]interface{}{
+ map[string]any{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
@@ -41,7 +41,7 @@ func TestJQ(t *testing.T) {
"price": 22.99,
},
},
- "bicycle": map[string]interface{}{
+ "bicycle": map[string]any{
"color": "red",
"price": 19.95,
},
@@ -76,14 +76,14 @@ func TestJQ(t *testing.T) {
out, err = JQ(ctx, ".store.book[]|select(.price < 10.0 )", in)
require.NoError(t, err)
- expected := []interface{}{
- map[string]interface{}{
+ expected := []any{
+ map[string]any{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95,
},
- map[string]interface{}{
+ map[string]any{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
@@ -93,20 +93,20 @@ func TestJQ(t *testing.T) {
}
assert.EqualValues(t, expected, out)
- in = map[string]interface{}{
- "a": map[string]interface{}{
- "aa": map[string]interface{}{
- "foo": map[string]interface{}{
- "aaa": map[string]interface{}{
- "aaaa": map[string]interface{}{
+ in = map[string]any{
+ "a": map[string]any{
+ "aa": map[string]any{
+ "foo": map[string]any{
+ "aaa": map[string]any{
+ "aaaa": map[string]any{
"bar": 1234,
},
},
},
},
- "ab": map[string]interface{}{
- "aba": map[string]interface{}{
- "foo": map[string]interface{}{
+ "ab": map[string]any{
+ "aba": map[string]any{
+ "foo": map[string]any{
"abaa": true,
"abab": "baz",
},
@@ -117,7 +117,7 @@ func TestJQ(t *testing.T) {
out, err = JQ(ctx, `tostream|select((.[0]|index("foo")) and (.[0][-1]!="foo") and (.[1])) as $s|($s[0]|index("foo")+1) as $ind|($ind|truncate_stream($s)) as $newstream|$newstream|reduce . as [$p,$v] ({};setpath($p;$v))|add`, in)
require.NoError(t, err)
assert.Len(t, out, 3)
- assert.Contains(t, out, map[string]interface{}{"aaaa": map[string]interface{}{"bar": 1234}})
+ assert.Contains(t, out, map[string]any{"aaaa": map[string]any{"bar": 1234}})
assert.Contains(t, out, true)
assert.Contains(t, out, "baz")
}
@@ -130,7 +130,7 @@ func TestJQ_typeConversions(t *testing.T) {
}
type storeType struct {
Bicycle *bicycleType
- safe interface{}
+ safe any
}
structIn := &storeType{
@@ -151,9 +151,9 @@ func TestJQ_typeConversions(t *testing.T) {
_, err = JQ(ctx, ".*", structIn)
require.Error(t, err)
- // a type with an underlying type of map[string]interface{}, just like
+ // a type with an underlying type of map[string]any, just like
// gomplate.tmplctx
- type mapType map[string]interface{}
+ type mapType map[string]any
out, err = JQ(ctx, ".foo", mapType{"foo": "bar"})
require.NoError(t, err)
@@ -165,7 +165,7 @@ func TestJQ_typeConversions(t *testing.T) {
assert.Equal(t, "bar", out)
// underlying slice type
- type sliceType []interface{}
+ type sliceType []any
out, err = JQ(ctx, ".[1]", sliceType{"foo", "bar"})
require.NoError(t, err)
@@ -216,9 +216,9 @@ func TestJQConvertType_passthroughTypes(t *testing.T) {
_, err := jqConvertType(v)
require.Error(t, err)
- testdata := []interface{}{
- map[string]interface{}{"foo": 1234},
- []interface{}{"foo", "bar", "baz", 1, 2, 3},
+ testdata := []any{
+ map[string]any{"foo": 1234},
+ []any{"foo", "bar", "baz", 1, 2, 3},
"foo",
[]byte("foo"),
json.RawMessage(`{"foo": "bar"}`),
diff --git a/coll/jsonpath.go b/coll/jsonpath.go
index 78ec5689..210280b6 100644
--- a/coll/jsonpath.go
+++ b/coll/jsonpath.go
@@ -8,7 +8,7 @@ import (
)
// JSONPath -
-func JSONPath(p string, in interface{}) (interface{}, error) {
+func JSONPath(p string, in any) (any, error) {
jp, err := parsePath(p)
if err != nil {
return nil, fmt.Errorf("couldn't parse JSONPath %s: %w", p, err)
@@ -18,7 +18,7 @@ func JSONPath(p string, in interface{}) (interface{}, error) {
return nil, fmt.Errorf("executing JSONPath failed: %w", err)
}
- var out interface{}
+ var out any
if len(results) == 1 && len(results[0]) == 1 {
v := results[0][0]
out, err = extractResult(v)
@@ -26,7 +26,7 @@ func JSONPath(p string, in interface{}) (interface{}, error) {
return nil, err
}
} else {
- a := []interface{}{}
+ a := []any{}
for _, r := range results {
for _, v := range r {
o, err := extractResult(v)
@@ -54,7 +54,7 @@ func parsePath(p string) (*jsonpath.JSONPath, error) {
return jp, nil
}
-func extractResult(v reflect.Value) (interface{}, error) {
+func extractResult(v reflect.Value) (any, error) {
if v.CanInterface() {
return v.Interface(), nil
}
diff --git a/coll/jsonpath_test.go b/coll/jsonpath_test.go
index a8bf02de..147fc2ea 100644
--- a/coll/jsonpath_test.go
+++ b/coll/jsonpath_test.go
@@ -8,8 +8,8 @@ import (
)
type (
- m = map[string]interface{}
- ar = []interface{}
+ m = map[string]any
+ ar = []any
)
func TestJSONPath(t *testing.T) {
@@ -127,7 +127,7 @@ func TestJSONPath(t *testing.T) {
}
type storeType struct {
Bicycle *bicycleType
- safe interface{}
+ safe any
}
structIn := &storeType{