-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmirror.go
57 lines (54 loc) · 1.41 KB
/
mirror.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// mirror - helps to make unsafe a little safer
//
// Copyright 2013 Arne Hormann. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package mirror
import (
"reflect"
)
// CanConvert returns true if the memory layout and the struct field names of
// 'from' match those of 'to'.
func CanConvert(from, to reflect.Type) bool {
switch {
case from.Kind() != reflect.Struct,
from.Kind() != to.Kind(),
from.Size() != to.Size(),
from.Name() != to.Name(),
from.NumField() != to.NumField():
return false
}
for i, max := 0, from.NumField(); i < max; i++ {
sf, tf := from.Field(i), to.Field(i)
if sf.Name != tf.Name || sf.Offset != tf.Offset {
return false
}
tsf, ttf := sf.Type, tf.Type
for done := false; !done; {
k := tsf.Kind()
if k != ttf.Kind() {
return false
}
switch k {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
tsf, ttf = tsf.Elem(), ttf.Elem()
case reflect.Interface:
// don't have to handle matching interfaces here
if tsf != ttf {
// there are none in our case, so we are extra strict
return false
}
case reflect.Struct:
if tsf.Name() != ttf.Name() {
return false
}
done = true
default:
done = true
}
}
}
return true
}