func()

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))
	}
}