"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 }