github.com/go-kivik/kivik/v4@v4.3.2/mockdb/gen/parse.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 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 // method contains the relevant information for a driver method. 25 type method struct { 26 // The method name 27 Name string 28 // Accepted values, except for context and options 29 Accepts []reflect.Type 30 // Return values, except for error 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 }