Skip to content

Commit 204c3a9

Browse files
moorereasonbep
authored andcommitted
tpl/collections: Support interfaces in union
Fixes #3411
1 parent fe901b8 commit 204c3a9

File tree

2 files changed

+112
-13
lines changed

2 files changed

+112
-13
lines changed

‎tpl/collections/collections.go‎

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ func (ns *Namespace) Slice(args ...interface{}) []interface{} {
545545
// If either l1 or l2 is nil then the non-nil list will be returned.
546546
func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
547547
if l1 == nil && l2 == nil {
548-
return nil, errors.New("both arrays/slices have to be of the same type")
548+
return []interface{}{}, nil
549549
} else if l1 == nil && l2 != nil {
550550
return l2, nil
551551
} else if l1 != nil && l2 == nil {
@@ -561,21 +561,96 @@ func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
561561
case reflect.Array, reflect.Slice:
562562
r := reflect.MakeSlice(l1v.Type(), 0, 0)
563563

564-
if l1v.Type() != l2v.Type() {
564+
if l1v.Type() != l2v.Type() &&
565+
l1v.Type().Elem().Kind() != reflect.Interface &&
566+
l2v.Type().Elem().Kind() != reflect.Interface {
567+
565568
return r.Interface(), nil
566569
}
567570

571+
var l1vv reflect.Value
568572
for i := 0; i < l1v.Len(); i++ {
569-
elem := l1v.Index(i)
570-
if !ns.In(r.Interface(), elem.Interface()) {
571-
r = reflect.Append(r, elem)
573+
l1vv = l1v.Index(i)
574+
if !ns.In(r.Interface(), l1vv.Interface()) {
575+
r = reflect.Append(r, l1vv)
572576
}
573577
}
574578

575579
for j := 0; j < l2v.Len(); j++ {
576-
elem := l2v.Index(j)
577-
if !ns.In(r.Interface(), elem.Interface()) {
578-
r = reflect.Append(r, elem)
580+
l2vv := l2v.Index(j)
581+
582+
switch l1vv.Kind() {
583+
case reflect.String:
584+
l2t, err := toString(l2vv)
585+
if err == nil && !ns.In(r.Interface(), l2t) {
586+
r = reflect.Append(r, reflect.ValueOf(l2t))
587+
}
588+
case reflect.Int:
589+
l2t, err := toInt(l2vv)
590+
if err == nil && !ns.In(r.Interface(), l2t) {
591+
r = reflect.Append(r, reflect.ValueOf(int(l2t)))
592+
}
593+
case reflect.Int8:
594+
l2t, err := toInt(l2vv)
595+
if err == nil && !ns.In(r.Interface(), l2t) {
596+
r = reflect.Append(r, reflect.ValueOf(int8(l2t)))
597+
}
598+
case reflect.Int16:
599+
l2t, err := toInt(l2vv)
600+
if err == nil && !ns.In(r.Interface(), l2t) {
601+
r = reflect.Append(r, reflect.ValueOf(int16(l2t)))
602+
}
603+
case reflect.Int32:
604+
l2t, err := toInt(l2vv)
605+
if err == nil && !ns.In(r.Interface(), l2t) {
606+
r = reflect.Append(r, reflect.ValueOf(int32(l2t)))
607+
}
608+
case reflect.Int64:
609+
l2t, err := toInt(l2vv)
610+
if err == nil && !ns.In(r.Interface(), l2t) {
611+
r = reflect.Append(r, reflect.ValueOf(l2t))
612+
}
613+
case reflect.Float32:
614+
l2t, err := toFloat(l2vv)
615+
if err == nil && !ns.In(r.Interface(), float32(l2t)) {
616+
r = reflect.Append(r, reflect.ValueOf(float32(l2t)))
617+
}
618+
case reflect.Float64:
619+
l2t, err := toFloat(l2vv)
620+
if err == nil && !ns.In(r.Interface(), l2t) {
621+
r = reflect.Append(r, reflect.ValueOf(l2t))
622+
}
623+
case reflect.Interface:
624+
switch l1vv.Interface().(type) {
625+
case string:
626+
switch l2vvActual := l2vv.Interface().(type) {
627+
case string:
628+
if !ns.In(r.Interface(), l2vvActual) {
629+
r = reflect.Append(r, l2vv)
630+
}
631+
}
632+
case int, int8, int16, int32, int64:
633+
switch l2vvActual := l2vv.Interface().(type) {
634+
case int, int8, int16, int32, int64:
635+
if !ns.In(r.Interface(), l2vvActual) {
636+
r = reflect.Append(r, l2vv)
637+
}
638+
}
639+
case uint, uint8, uint16, uint32, uint64:
640+
switch l2vvActual := l2vv.Interface().(type) {
641+
case uint, uint8, uint16, uint32, uint64:
642+
if !ns.In(r.Interface(), l2vvActual) {
643+
r = reflect.Append(r, l2vv)
644+
}
645+
}
646+
case float32, float64:
647+
switch l2vvActual := l2vv.Interface().(type) {
648+
case float32, float64:
649+
if !ns.In(r.Interface(), l2vvActual) {
650+
r = reflect.Append(r, l2vv)
651+
}
652+
}
653+
}
579654
}
580655
}
581656

‎tpl/collections/collections_test.go‎

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -571,21 +571,45 @@ func TestUnion(t *testing.T) {
571571
expect interface{}
572572
isErr bool
573573
}{
574+
{nil, nil, []interface{}{}, false},
575+
{nil, []string{"a", "b"}, []string{"a", "b"}, false},
576+
{[]string{"a", "b"}, nil, []string{"a", "b"}, false},
577+
578+
// []A ∪ []B
579+
{[]string{"1", "2"}, []int{3}, []string{}, false},
580+
{[]int{1, 2}, []string{"1", "2"}, []int{}, false},
581+
582+
// []T ∪ []T
574583
{[]string{"a", "b", "c", "c"}, []string{"a", "b", "b"}, []string{"a", "b", "c"}, false},
575584
{[]string{"a", "b"}, []string{"a", "b", "c"}, []string{"a", "b", "c"}, false},
576585
{[]string{"a", "b", "c"}, []string{"d", "e"}, []string{"a", "b", "c", "d", "e"}, false},
577586
{[]string{}, []string{}, []string{}, false},
578-
{[]string{"a", "b"}, nil, []string{"a", "b"}, false},
579-
{nil, []string{"a", "b"}, []string{"a", "b"}, false},
580-
{nil, nil, make([]interface{}, 0), true},
581-
{[]string{"1", "2"}, []int{1, 2}, make([]string, 0), false},
582-
{[]int{1, 2}, []string{"1", "2"}, make([]int, 0), false},
583587
{[]int{1, 2, 3}, []int{3, 4, 5}, []int{1, 2, 3, 4, 5}, false},
584588
{[]int{1, 2, 3}, []int{1, 2, 3}, []int{1, 2, 3}, false},
585589
{[]int{1, 2, 4}, []int{2, 4}, []int{1, 2, 4}, false},
586590
{[]int{2, 4}, []int{1, 2, 4}, []int{2, 4, 1}, false},
587591
{[]int{1, 2, 4}, []int{3, 6}, []int{1, 2, 4, 3, 6}, false},
588592
{[]float64{2.2, 4.4}, []float64{1.1, 2.2, 4.4}, []float64{2.2, 4.4, 1.1}, false},
593+
{[]interface{}{"a", "b", "c", "c"}, []interface{}{"a", "b", "b"}, []interface{}{"a", "b", "c"}, false},
594+
595+
// []T ∪ []interface{}
596+
{[]string{"1", "2"}, []interface{}{"9"}, []string{"1", "2", "9"}, false},
597+
{[]int{2, 4}, []interface{}{1, 2, 4}, []int{2, 4, 1}, false},
598+
{[]int8{2, 4}, []interface{}{int8(1), int8(2), int8(4)}, []int8{2, 4, 1}, false},
599+
{[]int8{2, 4}, []interface{}{1, 2, 4}, []int8{2, 4, 1}, false},
600+
{[]int16{2, 4}, []interface{}{1, 2, 4}, []int16{2, 4, 1}, false},
601+
{[]int32{2, 4}, []interface{}{1, 2, 4}, []int32{2, 4, 1}, false},
602+
{[]int64{2, 4}, []interface{}{1, 2, 4}, []int64{2, 4, 1}, false},
603+
{[]float64{2.2, 4.4}, []interface{}{1.1, 2.2, 4.4}, []float64{2.2, 4.4, 1.1}, false},
604+
{[]float32{2.2, 4.4}, []interface{}{1.1, 2.2, 4.4}, []float32{2.2, 4.4, 1.1}, false},
605+
606+
// []interface{} ∪ []T
607+
{[]interface{}{"a", "b", "c", "c"}, []string{"a", "b", "b"}, []interface{}{"a", "b", "c"}, false},
608+
{[]interface{}{}, []string{}, []interface{}{}, false},
609+
{[]interface{}{1, 2}, []int{2, 3}, []interface{}{1, 2, 3}, false},
610+
{[]interface{}{1, 2}, []int8{2, 3}, []interface{}{1, 2, int8(3)}, false},
611+
{[]interface{}{1.1, 2.2}, []float64{2.2, 3.3}, []interface{}{1.1, 2.2, 3.3}, false},
612+
589613
// errors
590614
{"not array or slice", []string{"a"}, false, true},
591615
{[]string{"a"}, "not array or slice", false, true},

0 commit comments

Comments
 (0)