in pkg/cloud/meta/method.go [183:250]
func (m *Method) init() {
fType := m.m.Func.Type()
if fType.NumIn() < m.argsSkip() {
err := fmt.Errorf("method %q.%q, arity = %d which is less than required (< %d)",
m.Service, m.Name(), fType.NumIn(), m.argsSkip())
panic(err)
}
// Skipped args should all be string (they will be projectID, zone, region etc).
for i := 1; i < m.argsSkip(); i++ {
if fType.In(i).Kind() != reflect.String {
panic(fmt.Errorf("method %q.%q: skipped args can only be strings", m.Service, m.Name()))
}
}
// Return of the method must return a single value of type *xxxCall.
if fType.NumOut() != 1 || fType.Out(0).Kind() != reflect.Pointer || !strings.HasSuffix(fType.Out(0).Elem().Name(), "Call") {
panic(fmt.Errorf("method %q.%q: generator only supports methods returning an *xxxCall object",
m.Service, m.Name()))
}
returnType := fType.Out(0)
returnTypeName := fType.Out(0).Elem().Name()
// xxxCall must have a Do() method.
doMethod, ok := returnType.MethodByName("Do")
if !ok {
panic(fmt.Errorf("method %q.%q: return type %q does not have a Do() method",
m.Service, m.Name(), returnTypeName))
}
_, hasPages := returnType.MethodByName("Pages")
// Do() method must return (*T, error).
switch doMethod.Func.Type().NumOut() {
case 2:
out0 := doMethod.Func.Type().Out(0)
if out0.Kind() != reflect.Pointer {
panic(fmt.Errorf("method %q.%q: return type %q of Do() = S, _; S must be pointer type (%v)",
m.Service, m.Name(), returnTypeName, out0))
}
m.ReturnType = out0.Elem().Name()
switch {
case out0.Elem().Name() == "Operation":
m.kind = MethodOperation
case hasPages:
m.kind = MethodPaged
// Pages() returns a xxxList that has the actual list
// of objects in the xxxList.Items field.
listType := out0.Elem()
itemsField, ok := listType.FieldByName("Items")
if !ok {
panic(fmt.Errorf("method %q.%q: paged return type %q does not have a .Items field", m.Service, m.Name(), listType.Name()))
}
// itemsField will be a []*ItemType. Dereference to
// extract the ItemType.
itemsType := itemsField.Type
if itemsType.Kind() != reflect.Slice || itemsType.Elem().Kind() != reflect.Pointer {
panic(fmt.Errorf("method %q.%q: paged return type %q.Items is not an array of pointers", m.Service, m.Name(), listType.Name()))
}
m.ItemType = itemsType.Elem().Elem().Name()
default:
m.kind = MethodGet
}
// Second argument must be "error".
if doMethod.Func.Type().Out(1).Name() != "error" {
panic(fmt.Errorf("method %q.%q: return type %q of Do() = S, T; T must be 'error'",
m.Service, m.Name(), returnTypeName))
}
default:
panic(fmt.Errorf("method %q.%q: %q Do() return type is not handled by the generator",
m.Service, m.Name(), returnTypeName))
}
}