-
Notifications
You must be signed in to change notification settings - Fork 0
/
typelinks.go
39 lines (35 loc) · 1.2 KB
/
typelinks.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
package protowire
import (
"fmt"
"reflect"
"unsafe"
)
//go:linkname typelinks reflect.typelinks
func typelinks() ([]unsafe.Pointer, [][]int32)
//go:linkname rtypeOff reflect.rtypeOff
func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer
// getImplements はreflectパッケージの非公開処理を用いて、与えられたinterfaceの実装を取得します
// TODO: コード生成などに着手するタイミングで実装の一覧を取得する関数を生成するようにしたい
func getImplements(iface reflect.Type) ([]reflect.Value, error) {
if iface.Kind() != reflect.Interface {
return nil, fmt.Errorf("iface must be interface, but %s", iface.Kind().String())
}
sections, offsets := typelinks()
if len(sections) != 1 {
return nil, fmt.Errorf("failed to get sections")
}
if len(offsets) != 1 {
return nil, fmt.Errorf("failed to get offsets")
}
implements := make([]reflect.Value, 0)
for i, base := range sections {
for _, offset := range offsets[i] {
typeAddr := rtypeOff(base, offset)
typ := reflect.TypeOf(*(*interface{})(unsafe.Pointer(&typeAddr)))
if typ.Implements(iface) {
implements = append(implements, reflect.New(typ.Elem()))
}
}
}
return implements, nil
}