Skip to content

Commit

Permalink
Merge pull request #3 from azumads/master
Browse files Browse the repository at this point in the history
support copy slice with ptr struct
  • Loading branch information
jinzhu committed Nov 1, 2014
2 parents 0f5b379 + f50af64 commit 6e12de4
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 5 deletions.
29 changes: 24 additions & 5 deletions copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import "reflect"

func Copy(copy_to interface{}, copy_from interface{}) (err error) {
var (
is_slice bool
from_typ reflect.Type
to_typ reflect.Type
elem_amount int
is_slice bool
from_typ reflect.Type
is_from_typ_ptr bool
to_typ reflect.Type
is_to_typ_ptr bool
elem_amount int
)

from := reflect.ValueOf(copy_from)
Expand All @@ -19,13 +21,22 @@ func Copy(copy_to interface{}, copy_from interface{}) (err error) {
is_slice = true
if from_elem.Kind() == reflect.Slice {
from_typ = from_elem.Type().Elem()
if from_typ.Kind() == reflect.Ptr {
from_typ = from_typ.Elem()
is_from_typ_ptr = true
}
elem_amount = from_elem.Len()
} else {
from_typ = from_elem.Type()
elem_amount = 1
}

to_typ = to_elem.Type().Elem()
if to_typ.Kind() == reflect.Ptr {
to_typ = to_typ.Elem()
is_to_typ_ptr = true
}

} else {
from_typ = from_elem.Type()
to_typ = to_elem.Type()
Expand All @@ -37,6 +48,9 @@ func Copy(copy_to interface{}, copy_from interface{}) (err error) {
if is_slice {
if from_elem.Kind() == reflect.Slice {
source = from_elem.Index(e)
if is_from_typ_ptr {
source = source.Elem()
}
} else {
source = from_elem
}
Expand Down Expand Up @@ -84,7 +98,12 @@ func Copy(copy_to interface{}, copy_from interface{}) (err error) {
}

if is_slice {
to_elem.Set(reflect.Append(to_elem, dest))
if is_to_typ_ptr {
to_elem.Set(reflect.Append(to_elem, dest.Addr()))
} else {
to_elem.Set(reflect.Append(to_elem, dest))
}

}
}
return
Expand Down
62 changes: 62 additions & 0 deletions copier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,68 @@ func TestCopySlice(t *testing.T) {
}
}

func TestCopySliceWithPtr(t *testing.T) {
user := User{Name: "Jinzhu", Age: 18, Role: "Admin", Notes: []string{"hello world"}}
user2 := &User{Name: "jinzhu 2", Age: 30, Role: "Dev"}
users := []*User{user2}
employees := []*Employee{}

Copy(&employees, &user)
if len(employees) != 1 {
t.Errorf("Should only have one elem when copy struct to slice")
}

Copy(&employees, &users)
if len(employees) != 2 {
t.Errorf("Should have two elems when copy additional slice to slice")
}

if employees[0].Name != "Jinzhu" {
t.Errorf("Name haven't been copied correctly.")
}
if employees[0].Age != 18 {
t.Errorf("Age haven't been copied correctly.")
}
if employees[0].DoubleAge != 36 {
t.Errorf("Copy copy from method doesn't work")
}
if employees[0].SuperRule != "Super Admin" {
t.Errorf("Copy Attributes should support copy to method")
}

if employees[1].Name != "jinzhu 2" {
t.Errorf("Name haven't been copied correctly.")
}
if employees[1].Age != 30 {
t.Errorf("Age haven't been copied correctly.")
}
if employees[1].DoubleAge != 60 {
t.Errorf("Copy copy from method doesn't work")
}
if employees[1].SuperRule != "Super Dev" {
t.Errorf("Copy Attributes should support copy to method")
}

employee := employees[0]
user.Notes = append(user.Notes, "welcome")
if !reflect.DeepEqual(user.Notes, []string{"hello world", "welcome"}) {
t.Errorf("User's Note should be changed")
}

if !reflect.DeepEqual(employee.Notes, []string{"hello world"}) {
t.Errorf("Employee's Note should not be changed")
}

employee.Notes = append(employee.Notes, "golang")
if !reflect.DeepEqual(employee.Notes, []string{"hello world", "golang"}) {
t.Errorf("Employee's Note should be changed")
}

if !reflect.DeepEqual(user.Notes, []string{"hello world", "welcome"}) {
t.Errorf("Employee's Note should not be changed")
}
}

func BenchmarkCopyStruct(b *testing.B) {
user := User{Name: "Jinzhu", Age: 18, Role: "Admin", Notes: []string{"hello world"}}
for x := 0; x < b.N; x++ {
Expand Down

0 comments on commit 6e12de4

Please sign in to comment.