func (g *Plugin) generateServerSignature(servName string, method *pb.MethodDescriptorProto) string {
	origMethName := method.GetName()
	methName := generator.CamelCase(origMethName)
	if reservedClientName[methName] {
		methName += "_"
	}
	var reqArgs []string
	ret := "error"
	if !method.GetServerStreaming() && !method.GetClientStreaming() {
		reqArgs = append(reqArgs, contextPkg+".Context")
		ret = "(*" + g.typeName(method.GetOutputType()) + ", error)"
	}
	if !method.GetClientStreaming() {
		reqArgs = append(reqArgs, "*"+g.typeName(method.GetInputType()))
	}
	if method.GetServerStreaming() || method.GetClientStreaming() {
		reqArgs = append(reqArgs, servName+"_"+generator.CamelCase(origMethName)+"Server")
	}
	return methName + "(" + strings.Join(reqArgs, ", ") + ") " + ret
}
generateServerSignature returns the server-side signature for a method.
package yarpc
import (
	"fmt"
	"path"
	"strconv"
	"strings"
	pb "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
	"github.com/influxdata/yarpc/cmd/protoc-gen-yarpc/generator"
	"github.com/influxdata/yarpc/yarpcproto"
)
const generatedCodeVersion = 1
const (
	contextPkgPath = "context"
	yarpcPkgPath   = "github.com/influxdata/yarpc"
)
type Plugin struct {
	gen *generator.Generator
}
var _ generator.Plugin = (*Plugin)(nil)
func (g *Plugin) Name() string {
	return "yarpc"
}
var (
	contextPkg string
	yarpcPkg   string
)
func (g *Plugin) Init(gen *generator.Generator) {
	g.gen = gen
	contextPkg = generator.RegisterUniquePackageName("context", nil)
	yarpcPkg = generator.RegisterUniquePackageName("yarpc", nil)
}
func (g *Plugin) objectNamed(name string) generator.Object {
	g.gen.RecordTypeUse(name)
	return g.gen.ObjectNamed(name)
}
func (g *Plugin) typeName(str string) string {
	return g.gen.TypeName(g.objectNamed(str))
}
func (g *Plugin) P(args ...interface{}) { g.gen.P(args...) }
func (g *Plugin) Generate(file *generator.FileDescriptor) {
	if len(file.FileDescriptorProto.Service) == 0 {
		return
	}
	g.P("// Reference imports to suppress errors if they are not otherwise used.")
	g.P("var _ ", contextPkg, ".Context")
	g.P("var _ ", yarpcPkg, ".ClientConn")
	g.P()
	g.P("// This is a compile-time assertion to ensure that this generated file")
	g.P("// is compatible with the yarpc package it is being compiled against.")
	g.P("const _ = ", yarpcPkg, ".SupportPackageIsVersion", generatedCodeVersion)
	g.P()
	for i, service := range file.FileDescriptorProto.Service {
		g.generateService(file, service, i)
	}
}
func (g *Plugin) GenerateImports(file *generator.FileDescriptor) {
	if len(file.FileDescriptorProto.Service) == 0 {
		return
	}
	g.P("import (")
	g.P(contextPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, contextPkgPath)))
	g.P(yarpcPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, yarpcPkgPath)))
	g.P(")")
	g.P()
}
var reservedClientName = map[string]bool{
}
func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] }
func (g *Plugin) getServiceIndex(service *pb.ServiceDescriptorProto) int {
	idx := yarpcproto.GetServiceIndex(service)
	if idx == -1 {
		g.gen.Error(fmt.Errorf("service %s missing yarpc_service_index option", service.GetName()))
	}
	if idx > 0xff {
		g.gen.Error(fmt.Errorf("service %s has invalid yarpc_service_index %d; must be less than 256", service.GetName(), idx))
	}
	return idx
}
func (g *Plugin) getMethodIndex(service *pb.ServiceDescriptorProto, method *pb.MethodDescriptorProto) int {
	idx := yarpcproto.GetMethodIndex(method)
	if idx == -1 {
		g.gen.Error(fmt.Errorf("method %s.%s missing yarpc_method_index option", service.GetName(), method.GetName()))
	}
	if idx > 0xff {
		g.gen.Error(fmt.Errorf("method %s.%s has invalid yarpc_method_index %d; must be less than 256", service.GetName(), method.GetName(), idx))
	}
	return idx
}
func (g *Plugin) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) {
	cpath := fmt.Sprintf("6,%d", index)  
	origServName := service.GetName()
	fullServName := origServName
	if pkg := file.GetPackage(); pkg != "" {
		fullServName = pkg + "." + fullServName
	}
	servName := generator.CamelCase(origServName)
	g.P()
	g.P("// Client API for ", servName, " service")
	g.P()
	g.P("type ", servName, "Client interface {")
	for i, method := range service.Method {
		g.gen.PrintComments(fmt.Sprintf("%s,2,%d", cpath, i))  
		g.P(g.generateClientSignature(servName, method))
	}
	g.P("}")
	g.P()
	g.P("type ", unexport(servName), "Client struct {")
	g.P("cc *", yarpcPkg, ".ClientConn")
	g.P("}")
	g.P()
	g.P("func New", servName, "Client (cc *", yarpcPkg, ".ClientConn) ", servName, "Client {")
	g.P("return &", unexport(servName), "Client{cc}")
	g.P("}")
	g.P()
	var methodIndex, streamIndex int
	serviceDescVar := "_" + servName + "_serviceDesc"
	for _, method := range service.Method {
		sidx := g.getServiceIndex(service)
		midx := g.getMethodIndex(service, method)
		var descExpr string
		if !method.GetServerStreaming() && !method.GetClientStreaming() {
			descExpr = fmt.Sprintf("&%s.Methods[%d]", serviceDescVar, methodIndex)
			methodIndex++
		} else {
			descExpr = fmt.Sprintf("&%s.Streams[%d]", serviceDescVar, streamIndex)
			streamIndex++
		}
		api := ((sidx << 8) | midx) & 0xffff
		g.generateClientMethod(servName, api, serviceDescVar, method, descExpr)
	}
	g.P("// Server API for ", servName, " service")
	g.P()
	serverType := servName + "Server"
	g.P("type ", serverType, " interface {")
	for i, method := range service.Method {
		g.gen.PrintComments(fmt.Sprintf("%s,2,%d", cpath, i))  
		g.P(g.generateServerSignature(servName, method))
	}
	g.P("}")
	g.P()
	g.P("func Register", servName, "Server(s *", yarpcPkg, ".Server, srv ", serverType, ") {")
	g.P("s.RegisterService(&", serviceDescVar, `, srv)`)
	g.P("}")
	g.P()
	var handlerNames []string
	for _, method := range service.Method {
		hname := g.generateServerMethod(servName, fullServName, method)
		handlerNames = append(handlerNames, hname)
	}
	sidx := g.getServiceIndex(service)
	g.P("var ", serviceDescVar, " = ", yarpcPkg, ".ServiceDesc {")
	g.P("ServiceName: ", strconv.Quote(fullServName), ",")
	g.P("Index: ", sidx, ",")
	g.P("HandlerType: (*", serverType, ")(nil),")
	g.P("Methods: []", yarpcPkg, ".MethodDesc{")
	for i, method := range service.Method {
		if method.GetServerStreaming() || method.GetClientStreaming() {
			continue
		}
		midx := g.getMethodIndex(service, method)
		g.P("{")
		g.P("MethodName: ", strconv.Quote(method.GetName()), ",")
		g.P("Index: ", midx, ",")
		g.P("Handler: ", handlerNames[i], ",")
		g.P("},")
	}
	g.P("},")
	g.P("Streams: []", yarpcPkg, ".StreamDesc{")
	for i, method := range service.Method {
		if !method.GetServerStreaming() && !method.GetClientStreaming() {
			continue
		}
		midx := g.getMethodIndex(service, method)
		g.P("{")
		g.P("StreamName: ", strconv.Quote(method.GetName()), ",")
		g.P("Index: ", midx, ",")
		g.P("Handler: ", handlerNames[i], ",")
		if method.GetServerStreaming() {
			g.P("ServerStreams: true,")
		}
		if method.GetClientStreaming() {
			g.P("ClientStreams: true,")
		}
		g.P("},")
	}
	g.P("},")
	g.P("Metadata: \"", file.GetName(), "\",")
	g.P("}")
	g.P()
}
func (g *Plugin) generateClientSignature(servName string, method *pb.MethodDescriptorProto) string {
	origMethName := method.GetName()
	methName := generator.CamelCase(origMethName)
	if reservedClientName[methName] {
		methName += "_"
	}
	reqArg := ", in *" + g.typeName(method.GetInputType())
	if method.GetClientStreaming() {
		reqArg = ""
	}
	respName := "*" + g.typeName(method.GetOutputType())
	if method.GetServerStreaming() || method.GetClientStreaming() {
		respName = servName + "_" + generator.CamelCase(origMethName) + "Client"
	}
	return fmt.Sprintf("%s(ctx %s.Context%s) (%s, error)", methName, contextPkg, reqArg, respName)
}
func (g *Plugin) generateClientMethod(servName string, api int, serviceDescVar string, method *pb.MethodDescriptorProto, descExpr string) {
	apihex := fmt.Sprintf("0x%04x", api)
	methName := generator.CamelCase(method.GetName())
	inType := g.typeName(method.GetInputType())
	outType := g.typeName(method.GetOutputType())
	g.P("func (c *", unexport(servName), "Client) ", g.generateClientSignature(servName, method), "{")
	if !method.GetServerStreaming() && !method.GetClientStreaming() {
		g.P("out := new(", outType, ")")
		g.P("err := ", yarpcPkg, `.Invoke(ctx, `, apihex, `, in, out, c.cc)`)
		g.P("if err != nil { return nil, err }")
		g.P("return out, nil")
		g.P("}")
		g.P()
		return
	}
	streamType := unexport(servName) + methName + "Client"
	g.P("stream, err := ", yarpcPkg, ".NewClientStream(ctx, ", descExpr, `, c.cc, `, apihex, `)`)
	g.P("if err != nil { return nil, err }")
	g.P("x := &", streamType, "{stream}")
	if !method.GetClientStreaming() {
		g.P("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }")
	}
	g.P("return x, nil")
	g.P("}")
	g.P()
	genSend := method.GetClientStreaming()
	genRecv := method.GetServerStreaming()
	genCloseAndRecv := !method.GetServerStreaming()
	g.P("type ", servName, "_", methName, "Client interface {")
	if genSend {
		g.P("Send(*", inType, ") error")
	}
	if genRecv {
		g.P("Recv() (*", outType, ", error)")
	}
	if genCloseAndRecv {
		g.P("CloseAndRecv() (*", outType, ", error)")
	}
	g.P(yarpcPkg, ".ClientStream")
	g.P("}")
	g.P()
	g.P("type ", streamType, " struct {")
	g.P(yarpcPkg, ".ClientStream")
	g.P("}")
	g.P()
	if genSend {
		g.P("func (x *", streamType, ") Send(m *", inType, ") error {")
		g.P("return x.ClientStream.SendMsg(m)")
		g.P("}")
		g.P()
	}
	if genRecv {
		g.P("func (x *", streamType, ") Recv() (*", outType, ", error) {")
		g.P("m := new(", outType, ")")
		g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }")
		g.P("return m, nil")
		g.P("}")
		g.P()
	}
	if genCloseAndRecv {
		g.P("func (x *", streamType, ") CloseAndRecv() (*", outType, ", error) {")
		g.P("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }")
		g.P("m := new(", outType, ")")
		g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }")
		g.P("return m, nil")
		g.P("}")
		g.P()
	}
}