github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/tpl/collections/collections.go (about)

     1  // Copyright 2019 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // Package collections provides template functions for manipulating collections
    15  // such as arrays, maps, and slices.
    16  package collections
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"html/template"
    22  	"math/rand"
    23  	"net/url"
    24  	"reflect"
    25  	"strings"
    26  	"time"
    27  
    28  	"errors"
    29  
    30  	"github.com/gohugoio/hugo/common/collections"
    31  	"github.com/gohugoio/hugo/common/maps"
    32  	"github.com/gohugoio/hugo/common/types"
    33  	"github.com/gohugoio/hugo/deps"
    34  	"github.com/gohugoio/hugo/helpers"
    35  	"github.com/gohugoio/hugo/langs"
    36  	"github.com/gohugoio/hugo/tpl/compare"
    37  	"github.com/spf13/cast"
    38  )
    39  
    40  func init() {
    41  	// htime.Now cannot be used here
    42  	rand.Seed(time.Now().UTC().UnixNano())
    43  }
    44  
    45  // New returns a new instance of the collections-namespaced template functions.
    46  func New(deps *deps.Deps) *Namespace {
    47  	language := deps.Conf.Language()
    48  	if language == nil {
    49  		panic("language must be set")
    50  	}
    51  	loc := langs.GetLocation(language)
    52  
    53  	return &Namespace{
    54  		loc:      loc,
    55  		sortComp: compare.New(loc, true),
    56  		deps:     deps,
    57  	}
    58  }
    59  
    60  // Namespace provides template functions for the "collections" namespace.
    61  type Namespace struct {
    62  	loc      *time.Location
    63  	sortComp *compare.Namespace
    64  	deps     *deps.Deps
    65  }
    66  
    67  // After returns all the items after the first n items in list l.
    68  func (ns *Namespace) After(n any, l any) (any, error) {
    69  	if n == nil || l == nil {
    70  		return nil, errors.New("both limit and seq must be provided")
    71  	}
    72  
    73  	nv, err := cast.ToIntE(n)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	if nv < 0 {
    79  		return nil, errors.New("sequence bounds out of range [" + cast.ToString(nv) + ":]")
    80  	}
    81  
    82  	lv := reflect.ValueOf(l)
    83  	lv, isNil := indirect(lv)
    84  	if isNil {
    85  		return nil, errors.New("can't iterate over a nil value")
    86  	}
    87  
    88  	switch lv.Kind() {
    89  	case reflect.Array, reflect.Slice, reflect.String:
    90  		// okay
    91  	default:
    92  		return nil, errors.New("can't iterate over " + reflect.ValueOf(l).Type().String())
    93  	}
    94  
    95  	if nv >= lv.Len() {
    96  		return lv.Slice(0, 0).Interface(), nil
    97  	}
    98  
    99  	return lv.Slice(nv, lv.Len()).Interface(), nil
   100  }
   101  
   102  // Delimit takes a given list l and returns a string delimited by sep.
   103  // If last is passed to the function, it will be used as the final delimiter.
   104  func (ns *Namespace) Delimit(ctx context.Context, l, sep any, last ...any) (template.HTML, error) {
   105  	d, err := cast.ToStringE(sep)
   106  	if err != nil {
   107  		return "", err
   108  	}
   109  
   110  	var dLast *string
   111  	if len(last) > 0 {
   112  		l := last[0]
   113  		dStr, err := cast.ToStringE(l)
   114  		if err != nil {
   115  			dLast = nil
   116  		} else {
   117  			dLast = &dStr
   118  		}
   119  	}
   120  
   121  	lv := reflect.ValueOf(l)
   122  	lv, isNil := indirect(lv)
   123  	if isNil {
   124  		return "", errors.New("can't iterate over a nil value")
   125  	}
   126  
   127  	var str string
   128  	switch lv.Kind() {
   129  	case reflect.Map:
   130  		sortSeq, err := ns.Sort(ctx, l)
   131  		if err != nil {
   132  			return "", err
   133  		}
   134  		lv = reflect.ValueOf(sortSeq)
   135  		fallthrough
   136  	case reflect.Array, reflect.Slice, reflect.String:
   137  		for i := 0; i < lv.Len(); i++ {
   138  			val := lv.Index(i).Interface()
   139  			valStr, err := cast.ToStringE(val)
   140  			if err != nil {
   141  				continue
   142  			}
   143  			switch {
   144  			case i == lv.Len()-2 && dLast != nil:
   145  				str += valStr + *dLast
   146  			case i == lv.Len()-1:
   147  				str += valStr
   148  			default:
   149  				str += valStr + d
   150  			}
   151  		}
   152  
   153  	default:
   154  		return "", fmt.Errorf("can't iterate over %v", l)
   155  	}
   156  
   157  	return template.HTML(str), nil
   158  }
   159  
   160  // Dictionary creates a new map from the given parameters by
   161  // treating values as key-value pairs.  The number of values must be even.
   162  // The keys can be string slices, which will create the needed nested structure.
   163  func (ns *Namespace) Dictionary(values ...any) (map[string]any, error) {
   164  	if len(values)%2 != 0 {
   165  		return nil, errors.New("invalid dictionary call")
   166  	}
   167  
   168  	root := make(map[string]any)
   169  
   170  	for i := 0; i < len(values); i += 2 {
   171  		dict := root
   172  		var key string
   173  		switch v := values[i].(type) {
   174  		case string:
   175  			key = v
   176  		case []string:
   177  			for i := 0; i < len(v)-1; i++ {
   178  				key = v[i]
   179  				var m map[string]any
   180  				v, found := dict[key]
   181  				if found {
   182  					m = v.(map[string]any)
   183  				} else {
   184  					m = make(map[string]any)
   185  					dict[key] = m
   186  				}
   187  				dict = m
   188  			}
   189  			key = v[len(v)-1]
   190  		default:
   191  			return nil, errors.New("invalid dictionary key")
   192  		}
   193  		dict[key] = values[i+1]
   194  	}
   195  
   196  	return root, nil
   197  }
   198  
   199  // EchoParam returns the value in the collection c with key k if is set; otherwise, it returns an
   200  // empty string.
   201  // Deprecated: Use the index function instead.
   202  func (ns *Namespace) EchoParam(c, k any) any {
   203  	helpers.Deprecated("collections.EchoParam", "Use the index function instead.", false)
   204  	av, isNil := indirect(reflect.ValueOf(c))
   205  	if isNil {
   206  		return ""
   207  	}
   208  
   209  	var avv reflect.Value
   210  	switch av.Kind() {
   211  	case reflect.Array, reflect.Slice:
   212  		index, ok := k.(int)
   213  		if ok && av.Len() > index {
   214  			avv = av.Index(index)
   215  		}
   216  	case reflect.Map:
   217  		kv := reflect.ValueOf(k)
   218  		if kv.Type().AssignableTo(av.Type().Key()) {
   219  			avv = av.MapIndex(kv)
   220  		}
   221  	}
   222  
   223  	avv, isNil = indirect(avv)
   224  
   225  	if isNil {
   226  		return ""
   227  	}
   228  
   229  	if avv.IsValid() {
   230  		switch avv.Kind() {
   231  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   232  			return avv.Int()
   233  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   234  			return avv.Uint()
   235  		case reflect.Float32, reflect.Float64:
   236  			return avv.Float()
   237  		case reflect.String:
   238  			return avv.String()
   239  		case reflect.Bool:
   240  			return avv.Bool()
   241  		}
   242  	}
   243  
   244  	return ""
   245  }
   246  
   247  // First returns the first limit items in list l.
   248  func (ns *Namespace) First(limit any, l any) (any, error) {
   249  	if limit == nil || l == nil {
   250  		return nil, errors.New("both limit and seq must be provided")
   251  	}
   252  
   253  	limitv, err := cast.ToIntE(limit)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	if limitv < 0 {
   259  		return nil, errors.New("sequence length must be non-negative")
   260  	}
   261  
   262  	lv := reflect.ValueOf(l)
   263  	lv, isNil := indirect(lv)
   264  	if isNil {
   265  		return nil, errors.New("can't iterate over a nil value")
   266  	}
   267  
   268  	switch lv.Kind() {
   269  	case reflect.Array, reflect.Slice, reflect.String:
   270  		// okay
   271  	default:
   272  		return nil, errors.New("can't iterate over " + reflect.ValueOf(l).Type().String())
   273  	}
   274  
   275  	if limitv > lv.Len() {
   276  		limitv = lv.Len()
   277  	}
   278  
   279  	return lv.Slice(0, limitv).Interface(), nil
   280  }
   281  
   282  // In returns whether v is in the list l.  l may be an array or slice.
   283  func (ns *Namespace) In(l any, v any) (bool, error) {
   284  	if l == nil || v == nil {
   285  		return false, nil
   286  	}
   287  
   288  	lv := reflect.ValueOf(l)
   289  	vv := reflect.ValueOf(v)
   290  
   291  	vvk := normalize(vv)
   292  
   293  	switch lv.Kind() {
   294  	case reflect.Array, reflect.Slice:
   295  		for i := 0; i < lv.Len(); i++ {
   296  			lvv, isNil := indirectInterface(lv.Index(i))
   297  			if isNil {
   298  				continue
   299  			}
   300  
   301  			lvvk := normalize(lvv)
   302  
   303  			if lvvk == vvk {
   304  				return true, nil
   305  			}
   306  		}
   307  	}
   308  	ss, err := cast.ToStringE(l)
   309  	if err != nil {
   310  		return false, nil
   311  	}
   312  
   313  	su, err := cast.ToStringE(v)
   314  	if err != nil {
   315  		return false, nil
   316  	}
   317  	return strings.Contains(ss, su), nil
   318  }
   319  
   320  // Intersect returns the common elements in the given sets, l1 and l2.  l1 and
   321  // l2 must be of the same type and may be either arrays or slices.
   322  func (ns *Namespace) Intersect(l1, l2 any) (any, error) {
   323  	if l1 == nil || l2 == nil {
   324  		return make([]any, 0), nil
   325  	}
   326  
   327  	var ins *intersector
   328  
   329  	l1v := reflect.ValueOf(l1)
   330  	l2v := reflect.ValueOf(l2)
   331  
   332  	switch l1v.Kind() {
   333  	case reflect.Array, reflect.Slice:
   334  		ins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[any]bool)}
   335  		switch l2v.Kind() {
   336  		case reflect.Array, reflect.Slice:
   337  			for i := 0; i < l1v.Len(); i++ {
   338  				l1vv := l1v.Index(i)
   339  				if !l1vv.Type().Comparable() {
   340  					return make([]any, 0), errors.New("intersect does not support slices or arrays of uncomparable types")
   341  				}
   342  
   343  				for j := 0; j < l2v.Len(); j++ {
   344  					l2vv := l2v.Index(j)
   345  					if !l2vv.Type().Comparable() {
   346  						return make([]any, 0), errors.New("intersect does not support slices or arrays of uncomparable types")
   347  					}
   348  
   349  					ins.handleValuePair(l1vv, l2vv)
   350  				}
   351  			}
   352  			return ins.r.Interface(), nil
   353  		default:
   354  			return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
   355  		}
   356  	default:
   357  		return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
   358  	}
   359  }
   360  
   361  // Group groups a set of items by the given key.
   362  // This is currently only supported for Pages.
   363  func (ns *Namespace) Group(key any, items any) (any, error) {
   364  	if key == nil {
   365  		return nil, errors.New("nil is not a valid key to group by")
   366  	}
   367  
   368  	if g, ok := items.(collections.Grouper); ok {
   369  		return g.Group(key, items)
   370  	}
   371  
   372  	in := newSliceElement(items)
   373  
   374  	if g, ok := in.(collections.Grouper); ok {
   375  		return g.Group(key, items)
   376  	}
   377  
   378  	return nil, fmt.Errorf("grouping not supported for type %T %T", items, in)
   379  }
   380  
   381  // IsSet returns whether a given array, channel, slice, or map in c has the given key
   382  // defined.
   383  func (ns *Namespace) IsSet(c any, key any) (bool, error) {
   384  	av := reflect.ValueOf(c)
   385  	kv := reflect.ValueOf(key)
   386  
   387  	switch av.Kind() {
   388  	case reflect.Array, reflect.Chan, reflect.Slice:
   389  		k, err := cast.ToIntE(key)
   390  		if err != nil {
   391  			return false, fmt.Errorf("isset unable to use key of type %T as index", key)
   392  		}
   393  		if av.Len() > k {
   394  			return true, nil
   395  		}
   396  	case reflect.Map:
   397  		if kv.Type() == av.Type().Key() {
   398  			return av.MapIndex(kv).IsValid(), nil
   399  		}
   400  	default:
   401  		ns.deps.Log.Warnf("calling IsSet with unsupported type %q (%T) will always return false.\n", av.Kind(), c)
   402  	}
   403  
   404  	return false, nil
   405  }
   406  
   407  // Last returns the last limit items in the list l.
   408  func (ns *Namespace) Last(limit any, l any) (any, error) {
   409  	if limit == nil || l == nil {
   410  		return nil, errors.New("both limit and seq must be provided")
   411  	}
   412  
   413  	limitv, err := cast.ToIntE(limit)
   414  	if err != nil {
   415  		return nil, err
   416  	}
   417  
   418  	if limitv < 0 {
   419  		return nil, errors.New("sequence length must be non-negative")
   420  	}
   421  
   422  	seqv := reflect.ValueOf(l)
   423  	seqv, isNil := indirect(seqv)
   424  	if isNil {
   425  		return nil, errors.New("can't iterate over a nil value")
   426  	}
   427  
   428  	switch seqv.Kind() {
   429  	case reflect.Array, reflect.Slice, reflect.String:
   430  		// okay
   431  	default:
   432  		return nil, errors.New("can't iterate over " + reflect.ValueOf(l).Type().String())
   433  	}
   434  
   435  	if limitv > seqv.Len() {
   436  		limitv = seqv.Len()
   437  	}
   438  
   439  	return seqv.Slice(seqv.Len()-limitv, seqv.Len()).Interface(), nil
   440  }
   441  
   442  // Querify encodes the given params in URL-encoded form ("bar=baz&foo=quux") sorted by key.
   443  func (ns *Namespace) Querify(params ...any) (string, error) {
   444  	qs := url.Values{}
   445  
   446  	if len(params) == 1 {
   447  		switch v := params[0].(type) {
   448  		case []string:
   449  			if len(v)%2 != 0 {
   450  				return "", errors.New("invalid query")
   451  			}
   452  
   453  			for i := 0; i < len(v); i += 2 {
   454  				qs.Add(v[i], v[i+1])
   455  			}
   456  
   457  			return qs.Encode(), nil
   458  
   459  		case []any:
   460  			params = v
   461  
   462  		default:
   463  			return "", errors.New("query keys must be strings")
   464  		}
   465  	}
   466  
   467  	if len(params)%2 != 0 {
   468  		return "", errors.New("invalid query")
   469  	}
   470  
   471  	for i := 0; i < len(params); i += 2 {
   472  		switch v := params[i].(type) {
   473  		case string:
   474  			qs.Add(v, fmt.Sprintf("%v", params[i+1]))
   475  		default:
   476  			return "", errors.New("query keys must be strings")
   477  		}
   478  	}
   479  
   480  	return qs.Encode(), nil
   481  }
   482  
   483  // Reverse creates a copy of the list l and reverses it.
   484  func (ns *Namespace) Reverse(l any) (any, error) {
   485  	if l == nil {
   486  		return nil, nil
   487  	}
   488  	v := reflect.ValueOf(l)
   489  
   490  	switch v.Kind() {
   491  	case reflect.Slice:
   492  	default:
   493  		return nil, errors.New("argument must be a slice")
   494  	}
   495  
   496  	sliceCopy := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
   497  
   498  	for i := v.Len() - 1; i >= 0; i-- {
   499  		element := sliceCopy.Index(i)
   500  		element.Set(v.Index(v.Len() - 1 - i))
   501  	}
   502  
   503  	return sliceCopy.Interface(), nil
   504  }
   505  
   506  // Seq creates a sequence of integers from args. It's named and used as GNU's seq.
   507  //
   508  // Examples:
   509  //
   510  //	3 => 1, 2, 3
   511  //	1 2 4 => 1, 3
   512  //	-3 => -1, -2, -3
   513  //	1 4 => 1, 2, 3, 4
   514  //	1 -2 => 1, 0, -1, -2
   515  func (ns *Namespace) Seq(args ...any) ([]int, error) {
   516  	if len(args) < 1 || len(args) > 3 {
   517  		return nil, errors.New("invalid number of arguments to Seq")
   518  	}
   519  
   520  	intArgs := cast.ToIntSlice(args)
   521  	if len(intArgs) < 1 || len(intArgs) > 3 {
   522  		return nil, errors.New("invalid arguments to Seq")
   523  	}
   524  
   525  	inc := 1
   526  	var last int
   527  	first := intArgs[0]
   528  
   529  	if len(intArgs) == 1 {
   530  		last = first
   531  		if last == 0 {
   532  			return []int{}, nil
   533  		} else if last > 0 {
   534  			first = 1
   535  		} else {
   536  			first = -1
   537  			inc = -1
   538  		}
   539  	} else if len(intArgs) == 2 {
   540  		last = intArgs[1]
   541  		if last < first {
   542  			inc = -1
   543  		}
   544  	} else {
   545  		inc = intArgs[1]
   546  		last = intArgs[2]
   547  		if inc == 0 {
   548  			return nil, errors.New("'increment' must not be 0")
   549  		}
   550  		if first < last && inc < 0 {
   551  			return nil, errors.New("'increment' must be > 0")
   552  		}
   553  		if first > last && inc > 0 {
   554  			return nil, errors.New("'increment' must be < 0")
   555  		}
   556  	}
   557  
   558  	// sanity check
   559  	if last < -100000 {
   560  		return nil, errors.New("size of result exceeds limit")
   561  	}
   562  	size := ((last - first) / inc) + 1
   563  
   564  	// sanity check
   565  	if size <= 0 || size > 2000 {
   566  		return nil, errors.New("size of result exceeds limit")
   567  	}
   568  
   569  	seq := make([]int, size)
   570  	val := first
   571  	for i := 0; ; i++ {
   572  		seq[i] = val
   573  		val += inc
   574  		if (inc < 0 && val < last) || (inc > 0 && val > last) {
   575  			break
   576  		}
   577  	}
   578  
   579  	return seq, nil
   580  }
   581  
   582  // Shuffle returns list l in a randomised order.
   583  func (ns *Namespace) Shuffle(l any) (any, error) {
   584  	if l == nil {
   585  		return nil, errors.New("both count and seq must be provided")
   586  	}
   587  
   588  	lv := reflect.ValueOf(l)
   589  	lv, isNil := indirect(lv)
   590  	if isNil {
   591  		return nil, errors.New("can't iterate over a nil value")
   592  	}
   593  
   594  	switch lv.Kind() {
   595  	case reflect.Array, reflect.Slice, reflect.String:
   596  		// okay
   597  	default:
   598  		return nil, errors.New("can't iterate over " + reflect.ValueOf(l).Type().String())
   599  	}
   600  
   601  	shuffled := reflect.MakeSlice(reflect.TypeOf(l), lv.Len(), lv.Len())
   602  
   603  	randomIndices := rand.Perm(lv.Len())
   604  
   605  	for index, value := range randomIndices {
   606  		shuffled.Index(value).Set(lv.Index(index))
   607  	}
   608  
   609  	return shuffled.Interface(), nil
   610  }
   611  
   612  // Slice returns a slice of all passed arguments.
   613  func (ns *Namespace) Slice(args ...any) any {
   614  	if len(args) == 0 {
   615  		return args
   616  	}
   617  
   618  	return collections.Slice(args...)
   619  }
   620  
   621  type intersector struct {
   622  	r    reflect.Value
   623  	seen map[any]bool
   624  }
   625  
   626  func (i *intersector) appendIfNotSeen(v reflect.Value) {
   627  	vi := v.Interface()
   628  	if !i.seen[vi] {
   629  		i.r = reflect.Append(i.r, v)
   630  		i.seen[vi] = true
   631  	}
   632  }
   633  
   634  func (i *intersector) handleValuePair(l1vv, l2vv reflect.Value) {
   635  	switch kind := l1vv.Kind(); {
   636  	case kind == reflect.String:
   637  		l2t, err := toString(l2vv)
   638  		if err == nil && l1vv.String() == l2t {
   639  			i.appendIfNotSeen(l1vv)
   640  		}
   641  	case isNumber(kind):
   642  		f1, err1 := numberToFloat(l1vv)
   643  		f2, err2 := numberToFloat(l2vv)
   644  		if err1 == nil && err2 == nil && f1 == f2 {
   645  			i.appendIfNotSeen(l1vv)
   646  		}
   647  	case kind == reflect.Ptr, kind == reflect.Struct:
   648  		if l1vv.Interface() == l2vv.Interface() {
   649  			i.appendIfNotSeen(l1vv)
   650  		}
   651  	case kind == reflect.Interface:
   652  		i.handleValuePair(reflect.ValueOf(l1vv.Interface()), l2vv)
   653  	}
   654  }
   655  
   656  // Union returns the union of the given sets, l1 and l2. l1 and
   657  // l2 must be of the same type and may be either arrays or slices.
   658  // If l1 and l2 aren't of the same type then l1 will be returned.
   659  // If either l1 or l2 is nil then the non-nil list will be returned.
   660  func (ns *Namespace) Union(l1, l2 any) (any, error) {
   661  	if l1 == nil && l2 == nil {
   662  		return []any{}, nil
   663  	} else if l1 == nil && l2 != nil {
   664  		return l2, nil
   665  	} else if l1 != nil && l2 == nil {
   666  		return l1, nil
   667  	}
   668  
   669  	l1v := reflect.ValueOf(l1)
   670  	l2v := reflect.ValueOf(l2)
   671  
   672  	var ins *intersector
   673  
   674  	switch l1v.Kind() {
   675  	case reflect.Array, reflect.Slice:
   676  		switch l2v.Kind() {
   677  		case reflect.Array, reflect.Slice:
   678  			ins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[any]bool)}
   679  
   680  			if l1v.Type() != l2v.Type() &&
   681  				l1v.Type().Elem().Kind() != reflect.Interface &&
   682  				l2v.Type().Elem().Kind() != reflect.Interface {
   683  				return ins.r.Interface(), nil
   684  			}
   685  
   686  			var (
   687  				l1vv  reflect.Value
   688  				isNil bool
   689  			)
   690  
   691  			for i := 0; i < l1v.Len(); i++ {
   692  				l1vv, isNil = indirectInterface(l1v.Index(i))
   693  
   694  				if !l1vv.Type().Comparable() {
   695  					return []any{}, errors.New("union does not support slices or arrays of uncomparable types")
   696  				}
   697  
   698  				if !isNil {
   699  					ins.appendIfNotSeen(l1vv)
   700  				}
   701  			}
   702  
   703  			if !l1vv.IsValid() {
   704  				// The first slice may be empty. Pick the first value of the second
   705  				// to use as a prototype.
   706  				if l2v.Len() > 0 {
   707  					l1vv = l2v.Index(0)
   708  				}
   709  			}
   710  
   711  			for j := 0; j < l2v.Len(); j++ {
   712  				l2vv := l2v.Index(j)
   713  
   714  				switch kind := l1vv.Kind(); {
   715  				case kind == reflect.String:
   716  					l2t, err := toString(l2vv)
   717  					if err == nil {
   718  						ins.appendIfNotSeen(reflect.ValueOf(l2t))
   719  					}
   720  				case isNumber(kind):
   721  					var err error
   722  					l2vv, err = convertNumber(l2vv, kind)
   723  					if err == nil {
   724  						ins.appendIfNotSeen(l2vv)
   725  					}
   726  				case kind == reflect.Interface, kind == reflect.Struct, kind == reflect.Ptr:
   727  					ins.appendIfNotSeen(l2vv)
   728  
   729  				}
   730  			}
   731  
   732  			return ins.r.Interface(), nil
   733  		default:
   734  			return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
   735  		}
   736  	default:
   737  		return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
   738  	}
   739  }
   740  
   741  // Uniq returns a new list with duplicate elements in the list l removed.
   742  func (ns *Namespace) Uniq(l any) (any, error) {
   743  	if l == nil {
   744  		return make([]any, 0), nil
   745  	}
   746  
   747  	v := reflect.ValueOf(l)
   748  	var slice reflect.Value
   749  
   750  	switch v.Kind() {
   751  	case reflect.Slice:
   752  		slice = reflect.MakeSlice(v.Type(), 0, 0)
   753  
   754  	case reflect.Array:
   755  		slice = reflect.MakeSlice(reflect.SliceOf(v.Type().Elem()), 0, 0)
   756  	default:
   757  		return nil, fmt.Errorf("type %T not supported", l)
   758  	}
   759  
   760  	seen := make(map[any]bool)
   761  
   762  	for i := 0; i < v.Len(); i++ {
   763  		ev, _ := indirectInterface(v.Index(i))
   764  
   765  		key := normalize(ev)
   766  
   767  		if _, found := seen[key]; !found {
   768  			slice = reflect.Append(slice, ev)
   769  			seen[key] = true
   770  		}
   771  	}
   772  
   773  	return slice.Interface(), nil
   774  }
   775  
   776  // KeyVals creates a key and values wrapper.
   777  func (ns *Namespace) KeyVals(key any, values ...any) (types.KeyValues, error) {
   778  	return types.KeyValues{Key: key, Values: values}, nil
   779  }
   780  
   781  // NewScratch creates a new Scratch which can be used to store values in a
   782  // thread safe way.
   783  func (ns *Namespace) NewScratch() *maps.Scratch {
   784  	return maps.NewScratch()
   785  }