1package main
2
3import "go/ast"
4
5// because "interface" is a keyword...
6type iface struct {
7	name, stubname, rcvrName *ast.Ident
8	methods                  []method
9}
10
11func (i iface) stubName() *ast.Ident {
12	return i.stubname
13}
14
15func (i iface) stubStructDecl() ast.Decl {
16	return structDecl(i.stubName(), &ast.FieldList{})
17}
18
19func (i iface) endpointsStruct() ast.Decl {
20	fl := &ast.FieldList{}
21	for _, m := range i.methods {
22		fl.List = append(fl.List, &ast.Field{Names: []*ast.Ident{m.name}, Type: sel(id("endpoint"), id("Endpoint"))})
23	}
24	return structDecl(id("Endpoints"), fl)
25}
26
27func (i iface) httpHandler() ast.Decl {
28	handlerFn := fetchFuncDecl("NewHTTPHandler")
29
30	// does this "inlining" process merit a helper akin to replaceIdent?
31	handleCalls := []ast.Stmt{}
32	for _, m := range i.methods {
33		handleCall := fetchFuncDecl("inlineHandlerBuilder").Body.List[0].(*ast.ExprStmt).X.(*ast.CallExpr)
34
35		handleCall = replaceLit(handleCall, `"/bar"`, `"`+m.pathName()+`"`).(*ast.CallExpr)
36		handleCall = replaceIdent(handleCall, "ExampleEndpoint", m.name).(*ast.CallExpr)
37		handleCall = replaceIdent(handleCall, "DecodeExampleRequest", m.decodeFuncName()).(*ast.CallExpr)
38		handleCall = replaceIdent(handleCall, "EncodeExampleResponse", m.encodeFuncName()).(*ast.CallExpr)
39
40		handleCalls = append(handleCalls, &ast.ExprStmt{X: handleCall})
41	}
42
43	pasteStmts(handlerFn.Body, 1, handleCalls)
44
45	return handlerFn
46}
47
48func (i iface) receiver() *ast.Field {
49	return field(i.receiverName(), i.stubName())
50}
51
52func (i iface) receiverName() *ast.Ident {
53	if i.rcvrName != nil {
54		return i.rcvrName
55	}
56	scope := ast.NewScope(nil)
57	for _, meth := range i.methods {
58		for _, arg := range meth.params {
59			if arg.name != nil {
60				scope.Insert(ast.NewObj(ast.Var, arg.name.Name))
61			}
62		}
63		for _, arg := range meth.results {
64			if arg.name != nil {
65				scope.Insert(ast.NewObj(ast.Var, arg.name.Name))
66			}
67		}
68	}
69	return id(unexport(inventName(i.name, scope).Name))
70}
71