URI: 
       tpl/collections: Support interfaces in union - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 204c3a9e32fcf6617ede978e35d3e2e89a5b491c
   DIR parent fe901b81191860b60e6fcb29f8ebf87baef2ee79
  HTML Author: Cameron Moore <moorereason@gmail.com>
       Date:   Sat, 20 May 2017 11:54:13 -0500
       
       tpl/collections: Support interfaces in union
       
       Fixes #3411
       
       Diffstat:
         M tpl/collections/collections.go      |      91 ++++++++++++++++++++++++++++---
         M tpl/collections/collections_test.go |      34 ++++++++++++++++++++++++++-----
       
       2 files changed, 112 insertions(+), 13 deletions(-)
       ---
   DIR diff --git a/tpl/collections/collections.go b/tpl/collections/collections.go
       @@ -545,7 +545,7 @@ func (ns *Namespace) Slice(args ...interface{}) []interface{} {
        // If either l1 or l2 is nil then the non-nil list will be returned.
        func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
                if l1 == nil && l2 == nil {
       -                return nil, errors.New("both arrays/slices have to be of the same type")
       +                return []interface{}{}, nil
                } else if l1 == nil && l2 != nil {
                        return l2, nil
                } else if l1 != nil && l2 == nil {
       @@ -561,21 +561,96 @@ func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
                        case reflect.Array, reflect.Slice:
                                r := reflect.MakeSlice(l1v.Type(), 0, 0)
        
       -                        if l1v.Type() != l2v.Type() {
       +                        if l1v.Type() != l2v.Type() &&
       +                                l1v.Type().Elem().Kind() != reflect.Interface &&
       +                                l2v.Type().Elem().Kind() != reflect.Interface {
       +
                                        return r.Interface(), nil
                                }
        
       +                        var l1vv reflect.Value
                                for i := 0; i < l1v.Len(); i++ {
       -                                elem := l1v.Index(i)
       -                                if !ns.In(r.Interface(), elem.Interface()) {
       -                                        r = reflect.Append(r, elem)
       +                                l1vv = l1v.Index(i)
       +                                if !ns.In(r.Interface(), l1vv.Interface()) {
       +                                        r = reflect.Append(r, l1vv)
                                        }
                                }
        
                                for j := 0; j < l2v.Len(); j++ {
       -                                elem := l2v.Index(j)
       -                                if !ns.In(r.Interface(), elem.Interface()) {
       -                                        r = reflect.Append(r, elem)
       +                                l2vv := l2v.Index(j)
       +
       +                                switch l1vv.Kind() {
       +                                case reflect.String:
       +                                        l2t, err := toString(l2vv)
       +                                        if err == nil && !ns.In(r.Interface(), l2t) {
       +                                                r = reflect.Append(r, reflect.ValueOf(l2t))
       +                                        }
       +                                case reflect.Int:
       +                                        l2t, err := toInt(l2vv)
       +                                        if err == nil && !ns.In(r.Interface(), l2t) {
       +                                                r = reflect.Append(r, reflect.ValueOf(int(l2t)))
       +                                        }
       +                                case reflect.Int8:
       +                                        l2t, err := toInt(l2vv)
       +                                        if err == nil && !ns.In(r.Interface(), l2t) {
       +                                                r = reflect.Append(r, reflect.ValueOf(int8(l2t)))
       +                                        }
       +                                case reflect.Int16:
       +                                        l2t, err := toInt(l2vv)
       +                                        if err == nil && !ns.In(r.Interface(), l2t) {
       +                                                r = reflect.Append(r, reflect.ValueOf(int16(l2t)))
       +                                        }
       +                                case reflect.Int32:
       +                                        l2t, err := toInt(l2vv)
       +                                        if err == nil && !ns.In(r.Interface(), l2t) {
       +                                                r = reflect.Append(r, reflect.ValueOf(int32(l2t)))
       +                                        }
       +                                case reflect.Int64:
       +                                        l2t, err := toInt(l2vv)
       +                                        if err == nil && !ns.In(r.Interface(), l2t) {
       +                                                r = reflect.Append(r, reflect.ValueOf(l2t))
       +                                        }
       +                                case reflect.Float32:
       +                                        l2t, err := toFloat(l2vv)
       +                                        if err == nil && !ns.In(r.Interface(), float32(l2t)) {
       +                                                r = reflect.Append(r, reflect.ValueOf(float32(l2t)))
       +                                        }
       +                                case reflect.Float64:
       +                                        l2t, err := toFloat(l2vv)
       +                                        if err == nil && !ns.In(r.Interface(), l2t) {
       +                                                r = reflect.Append(r, reflect.ValueOf(l2t))
       +                                        }
       +                                case reflect.Interface:
       +                                        switch l1vv.Interface().(type) {
       +                                        case string:
       +                                                switch l2vvActual := l2vv.Interface().(type) {
       +                                                case string:
       +                                                        if !ns.In(r.Interface(), l2vvActual) {
       +                                                                r = reflect.Append(r, l2vv)
       +                                                        }
       +                                                }
       +                                        case int, int8, int16, int32, int64:
       +                                                switch l2vvActual := l2vv.Interface().(type) {
       +                                                case int, int8, int16, int32, int64:
       +                                                        if !ns.In(r.Interface(), l2vvActual) {
       +                                                                r = reflect.Append(r, l2vv)
       +                                                        }
       +                                                }
       +                                        case uint, uint8, uint16, uint32, uint64:
       +                                                switch l2vvActual := l2vv.Interface().(type) {
       +                                                case uint, uint8, uint16, uint32, uint64:
       +                                                        if !ns.In(r.Interface(), l2vvActual) {
       +                                                                r = reflect.Append(r, l2vv)
       +                                                        }
       +                                                }
       +                                        case float32, float64:
       +                                                switch l2vvActual := l2vv.Interface().(type) {
       +                                                case float32, float64:
       +                                                        if !ns.In(r.Interface(), l2vvActual) {
       +                                                                r = reflect.Append(r, l2vv)
       +                                                        }
       +                                                }
       +                                        }
                                        }
                                }
        
   DIR diff --git a/tpl/collections/collections_test.go b/tpl/collections/collections_test.go
       @@ -571,21 +571,45 @@ func TestUnion(t *testing.T) {
                        expect interface{}
                        isErr  bool
                }{
       +                {nil, nil, []interface{}{}, false},
       +                {nil, []string{"a", "b"}, []string{"a", "b"}, false},
       +                {[]string{"a", "b"}, nil, []string{"a", "b"}, false},
       +
       +                // []A ∪ []B
       +                {[]string{"1", "2"}, []int{3}, []string{}, false},
       +                {[]int{1, 2}, []string{"1", "2"}, []int{}, false},
       +
       +                // []T ∪ []T
                        {[]string{"a", "b", "c", "c"}, []string{"a", "b", "b"}, []string{"a", "b", "c"}, false},
                        {[]string{"a", "b"}, []string{"a", "b", "c"}, []string{"a", "b", "c"}, false},
                        {[]string{"a", "b", "c"}, []string{"d", "e"}, []string{"a", "b", "c", "d", "e"}, false},
                        {[]string{}, []string{}, []string{}, false},
       -                {[]string{"a", "b"}, nil, []string{"a", "b"}, false},
       -                {nil, []string{"a", "b"}, []string{"a", "b"}, false},
       -                {nil, nil, make([]interface{}, 0), true},
       -                {[]string{"1", "2"}, []int{1, 2}, make([]string, 0), false},
       -                {[]int{1, 2}, []string{"1", "2"}, make([]int, 0), false},
                        {[]int{1, 2, 3}, []int{3, 4, 5}, []int{1, 2, 3, 4, 5}, false},
                        {[]int{1, 2, 3}, []int{1, 2, 3}, []int{1, 2, 3}, false},
                        {[]int{1, 2, 4}, []int{2, 4}, []int{1, 2, 4}, false},
                        {[]int{2, 4}, []int{1, 2, 4}, []int{2, 4, 1}, false},
                        {[]int{1, 2, 4}, []int{3, 6}, []int{1, 2, 4, 3, 6}, false},
                        {[]float64{2.2, 4.4}, []float64{1.1, 2.2, 4.4}, []float64{2.2, 4.4, 1.1}, false},
       +                {[]interface{}{"a", "b", "c", "c"}, []interface{}{"a", "b", "b"}, []interface{}{"a", "b", "c"}, false},
       +
       +                // []T ∪ []interface{}
       +                {[]string{"1", "2"}, []interface{}{"9"}, []string{"1", "2", "9"}, false},
       +                {[]int{2, 4}, []interface{}{1, 2, 4}, []int{2, 4, 1}, false},
       +                {[]int8{2, 4}, []interface{}{int8(1), int8(2), int8(4)}, []int8{2, 4, 1}, false},
       +                {[]int8{2, 4}, []interface{}{1, 2, 4}, []int8{2, 4, 1}, false},
       +                {[]int16{2, 4}, []interface{}{1, 2, 4}, []int16{2, 4, 1}, false},
       +                {[]int32{2, 4}, []interface{}{1, 2, 4}, []int32{2, 4, 1}, false},
       +                {[]int64{2, 4}, []interface{}{1, 2, 4}, []int64{2, 4, 1}, false},
       +                {[]float64{2.2, 4.4}, []interface{}{1.1, 2.2, 4.4}, []float64{2.2, 4.4, 1.1}, false},
       +                {[]float32{2.2, 4.4}, []interface{}{1.1, 2.2, 4.4}, []float32{2.2, 4.4, 1.1}, false},
       +
       +                // []interface{} ∪ []T
       +                {[]interface{}{"a", "b", "c", "c"}, []string{"a", "b", "b"}, []interface{}{"a", "b", "c"}, false},
       +                {[]interface{}{}, []string{}, []interface{}{}, false},
       +                {[]interface{}{1, 2}, []int{2, 3}, []interface{}{1, 2, 3}, false},
       +                {[]interface{}{1, 2}, []int8{2, 3}, []interface{}{1, 2, int8(3)}, false},
       +                {[]interface{}{1.1, 2.2}, []float64{2.2, 3.3}, []interface{}{1.1, 2.2, 3.3}, false},
       +
                        // errors
                        {"not array or slice", []string{"a"}, false, true},
                        {[]string{"a"}, "not array or slice", false, true},