hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

collections.go (18509B)

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