"Fossies" - the Fresh Open Source Software Archive

Member "hugo-0.62.2/common/collections/append.go" (5 Jan 2020, 2986 Bytes) of package /linux/www/hugo-0.62.2.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. See also the last Fossies "Diffs" side-by-side code changes report for "append.go": 0.58.3_vs_0.59.0.

    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 interface{}, from ...interface{}) (interface{}, 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 
   60     if toIsNil {
   61         return Slice(from...), nil
   62     }
   63 
   64     for _, f := range from {
   65         fv := reflect.ValueOf(f)
   66         if !fv.Type().AssignableTo(tot) {
   67             // Fall back to a []interface{} slice.
   68             tov, _ := indirect(reflect.ValueOf(to))
   69             return appendToInterfaceSlice(tov, from...)
   70         }
   71         tov = reflect.Append(tov, fv)
   72     }
   73 
   74     return tov.Interface(), nil
   75 }
   76 
   77 func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]interface{}, error) {
   78     var tos []interface{}
   79 
   80     for _, slice := range []reflect.Value{slice1, slice2} {
   81         for i := 0; i < slice.Len(); i++ {
   82             tos = append(tos, slice.Index(i).Interface())
   83         }
   84     }
   85 
   86     return tos, nil
   87 }
   88 
   89 func appendToInterfaceSlice(tov reflect.Value, from ...interface{}) ([]interface{}, error) {
   90     var tos []interface{}
   91 
   92     for i := 0; i < tov.Len(); i++ {
   93         tos = append(tos, tov.Index(i).Interface())
   94     }
   95 
   96     tos = append(tos, from...)
   97 
   98     return tos, nil
   99 }
  100 
  101 // indirect is borrowed from the Go stdlib: 'text/template/exec.go'
  102 // TODO(bep) consolidate
  103 func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
  104     for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
  105         if v.IsNil() {
  106             return v, true
  107         }
  108         if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
  109             break
  110         }
  111     }
  112     return v, false
  113 }