"Fossies" - the Fresh Open Source Software Archive

Member "hugo-0.113.0/common/collections/append.go" (5 Jun 2023, 2921 Bytes) of package /linux/www/hugo-0.113.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    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
   15 
   16 import (
   17     "fmt"
   18     "reflect"
   19 )
   20 
   21 // Append appends from to a slice to and returns the resulting slice.
   22 // If length of from is one and the only element is a slice of same type as to,
   23 // it will be appended.
   24 func Append(to any, from ...any) (any, error) {
   25     tov, toIsNil := indirect(reflect.ValueOf(to))
   26 
   27     toIsNil = toIsNil || to == nil
   28     var tot reflect.Type
   29 
   30     if !toIsNil {
   31         if tov.Kind() != reflect.Slice {
   32             return nil, fmt.Errorf("expected a slice, got %T", to)
   33         }
   34 
   35         tot = tov.Type().Elem()
   36         toIsNil = tov.Len() == 0
   37 
   38         if len(from) == 1 {
   39             fromv := reflect.ValueOf(from[0])
   40             if fromv.Kind() == reflect.Slice {
   41                 if toIsNil {
   42                     // If we get nil []string, we just return the []string
   43                     return from[0], nil
   44                 }
   45 
   46                 fromt := reflect.TypeOf(from[0]).Elem()
   47 
   48                 // If we get []string []string, we append the from slice to to
   49                 if tot == fromt {
   50                     return reflect.AppendSlice(tov, fromv).Interface(), nil
   51                 } else if !fromt.AssignableTo(tot) {
   52                     // Fall back to a []interface{} slice.
   53                     return appendToInterfaceSliceFromValues(tov, fromv)
   54                 }
   55             }
   56         }
   57     }
   58 
   59     if toIsNil {
   60         return Slice(from...), nil
   61     }
   62 
   63     for _, f := range from {
   64         fv := reflect.ValueOf(f)
   65         if !fv.Type().AssignableTo(tot) {
   66             // Fall back to a []interface{} slice.
   67             tov, _ := indirect(reflect.ValueOf(to))
   68             return appendToInterfaceSlice(tov, from...)
   69         }
   70         tov = reflect.Append(tov, fv)
   71     }
   72 
   73     return tov.Interface(), nil
   74 }
   75 
   76 func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]any, error) {
   77     var tos []any
   78 
   79     for _, slice := range []reflect.Value{slice1, slice2} {
   80         for i := 0; i < slice.Len(); i++ {
   81             tos = append(tos, slice.Index(i).Interface())
   82         }
   83     }
   84 
   85     return tos, nil
   86 }
   87 
   88 func appendToInterfaceSlice(tov reflect.Value, from ...any) ([]any, error) {
   89     var tos []any
   90 
   91     for i := 0; i < tov.Len(); i++ {
   92         tos = append(tos, tov.Index(i).Interface())
   93     }
   94 
   95     tos = append(tos, from...)
   96 
   97     return tos, nil
   98 }
   99 
  100 // indirect is borrowed from the Go stdlib: 'text/template/exec.go'
  101 // TODO(bep) consolidate
  102 func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
  103     for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
  104         if v.IsNil() {
  105             return v, true
  106         }
  107         if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
  108             break
  109         }
  110     }
  111     return v, false
  112 }