...
1
2
3
4
5
6
7
8
9
10
11
12
13 package main
14
15 import (
16 "context"
17 "errors"
18 "reflect"
19
20 kivik "github.com/go-kivik/kivik/v4"
21 "github.com/go-kivik/kivik/v4/driver"
22 )
23
24
25 type method struct {
26
27 Name string
28
29 Accepts []reflect.Type
30
31 Returns []reflect.Type
32 AcceptsContext bool
33 AcceptsOptions bool
34 ReturnsError bool
35 DBMethod bool
36 }
37
38 var (
39 typeContext = reflect.TypeOf((*context.Context)(nil)).Elem()
40 typeDriverOptions = reflect.TypeOf((*driver.Options)(nil)).Elem()
41 typeClientOptions = reflect.TypeOf([]kivik.Option{})
42 typeError = reflect.TypeOf((*error)(nil)).Elem()
43 typeString = reflect.TypeOf("")
44 )
45
46 func parseMethods(input interface{}, isClient bool, skip map[string]struct{}) ([]*method, error) {
47 var hasReceiver bool
48 t := reflect.TypeOf(input)
49 if t.Kind() != reflect.Struct {
50 return nil, errors.New("input must be struct")
51 }
52 if t.NumField() != 1 || t.Field(0).Name != "X" {
53 return nil, errors.New("wrapper struct must have a single field: X")
54 }
55 fType := t.Field(0).Type
56 if isClient {
57 if fType.Kind() != reflect.Ptr {
58 return nil, errors.New("field X must be of type pointer to struct")
59 }
60 if fType.Elem().Kind() != reflect.Struct {
61 return nil, errors.New("field X must be of type pointer to struct")
62 }
63 hasReceiver = true
64 } else if fType.Kind() != reflect.Interface {
65 return nil, errors.New("field X must be of type interface")
66 }
67 result := make([]*method, 0, fType.NumMethod())
68 for i := 0; i < fType.NumMethod(); i++ {
69 m := fType.Method(i)
70 if _, ok := skip[m.Name]; ok {
71 continue
72 }
73 dm := &method{
74 Name: m.Name,
75 }
76 result = append(result, dm)
77 accepts := make([]reflect.Type, m.Type.NumIn())
78 for j := 0; j < m.Type.NumIn(); j++ {
79 accepts[j] = m.Type.In(j)
80 }
81 if hasReceiver {
82 accepts = accepts[1:]
83 }
84 if len(accepts) > 0 && accepts[0].Kind() == reflect.Interface && accepts[0].Implements(typeContext) {
85 dm.AcceptsContext = true
86 accepts = accepts[1:]
87 }
88 if !isClient && len(accepts) > 0 && accepts[len(accepts)-1] == typeDriverOptions {
89 dm.AcceptsOptions = true
90 accepts = accepts[:len(accepts)-1]
91 }
92 if isClient && m.Type.IsVariadic() && len(accepts) > 0 && accepts[len(accepts)-1].String() == typeClientOptions.String() {
93 dm.AcceptsOptions = true
94 accepts = accepts[:len(accepts)-1]
95 }
96 if len(accepts) > 0 {
97 dm.Accepts = accepts
98 }
99
100 returns := make([]reflect.Type, m.Type.NumOut())
101 for j := 0; j < m.Type.NumOut(); j++ {
102 returns[j] = m.Type.Out(j)
103 }
104 if len(returns) > 0 && returns[len(returns)-1] == typeError {
105 dm.ReturnsError = true
106 returns = returns[:len(returns)-1]
107 }
108 if len(returns) > 0 {
109 dm.Returns = returns
110 }
111 }
112 return result, nil
113 }
114
View as plain text