github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/common/collections/slice.go (about)

     1  // Copyright 2018 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
    15  
    16  import (
    17  	"reflect"
    18  )
    19  
    20  // Slicer defines a very generic way to create a typed slice. This is used
    21  // in collections.Slice template func to get types such as Pages, PageGroups etc.
    22  // instead of the less useful []interface{}.
    23  type Slicer interface {
    24  	Slice(items interface{}) (interface{}, error)
    25  }
    26  
    27  // Slice returns a slice of all passed arguments.
    28  func Slice(args ...interface{}) interface{} {
    29  	if len(args) == 0 {
    30  		return args
    31  	}
    32  
    33  	first := args[0]
    34  	firstType := reflect.TypeOf(first)
    35  
    36  	if firstType == nil {
    37  		return args
    38  	}
    39  
    40  	if g, ok := first.(Slicer); ok {
    41  		v, err := g.Slice(args)
    42  		if err == nil {
    43  			return v
    44  		}
    45  
    46  		// If Slice fails, the items are not of the same type and
    47  		// []interface{} is the best we can do.
    48  		return args
    49  	}
    50  
    51  	if len(args) > 1 {
    52  		// This can be a mix of types.
    53  		for i := 1; i < len(args); i++ {
    54  			if firstType != reflect.TypeOf(args[i]) {
    55  				// []interface{} is the best we can do
    56  				return args
    57  			}
    58  		}
    59  	}
    60  
    61  	slice := reflect.MakeSlice(reflect.SliceOf(firstType), len(args), len(args))
    62  	for i, arg := range args {
    63  		slice.Index(i).Set(reflect.ValueOf(arg))
    64  	}
    65  	return slice.Interface()
    66  }
    67  
    68  // StringSliceToInterfaceSlice converts ss to []interface{}.
    69  func StringSliceToInterfaceSlice(ss []string) []interface{} {
    70  	result := make([]interface{}, len(ss))
    71  	for i, s := range ss {
    72  		result[i] = s
    73  	}
    74  	return result
    75  
    76  }