func (s *ServerStream) Context() context.Context {
	return s.stream.Context()
}
Context returns the context associated with this streaming operation.
package grpcdynamic
import (
	"fmt"
	"io"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	"github.com/jhump/protoreflect/desc"
	"github.com/jhump/protoreflect/dynamic"
)
type Stub struct {
	channel Channel
	mf      *dynamic.MessageFactory
}
type Channel interface {
	Invoke(ctx context.Context, method string, args, reply interface{}, opts ...grpc.CallOption) error
	NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error)
}
var _ Channel = (*grpc.ClientConn)(nil)
func NewStub(channel Channel) Stub {
	return NewStubWithMessageFactory(channel, nil)
}
func NewStubWithMessageFactory(channel Channel, mf *dynamic.MessageFactory) Stub {
	return Stub{channel: channel, mf: mf}
}
func requestMethod(md *desc.MethodDescriptor) string {
	return fmt.Sprintf("/%s/%s", md.GetService().GetFullyQualifiedName(), md.GetName())
}
func (s Stub) InvokeRpc(ctx context.Context, method *desc.MethodDescriptor, request proto.Message, opts ...grpc.CallOption) (proto.Message, error) {
	if method.IsClientStreaming() || method.IsServerStreaming() {
		return nil, fmt.Errorf("InvokeRpc is for unary methods; %q is %s", method.GetFullyQualifiedName(), methodType(method))
	}
	if err := checkMessageType(method.GetInputType(), request); err != nil {
		return nil, err
	}
	resp := s.mf.NewMessage(method.GetOutputType())
	if err := s.channel.Invoke(ctx, requestMethod(method), request, resp, opts...); err != nil {
		return nil, err
	}
	return resp, nil
}
func (s Stub) InvokeRpcServerStream(ctx context.Context, method *desc.MethodDescriptor, request proto.Message, opts ...grpc.CallOption) (*ServerStream, error) {
	if method.IsClientStreaming() || !method.IsServerStreaming() {
		return nil, fmt.Errorf("InvokeRpcServerStream is for server-streaming methods; %q is %s", method.GetFullyQualifiedName(), methodType(method))
	}
	if err := checkMessageType(method.GetInputType(), request); err != nil {
		return nil, err
	}
	ctx, cancel := context.WithCancel(ctx)
	sd := grpc.StreamDesc{
		StreamName:    method.GetName(),
		ServerStreams: method.IsServerStreaming(),
		ClientStreams: method.IsClientStreaming(),
	}
	if cs, err := s.channel.NewStream(ctx, &sd, requestMethod(method), opts...); err != nil {
		return nil, err
	} else {
		err = cs.SendMsg(request)
		if err != nil {
			cancel()
			return nil, err
		}
		err = cs.CloseSend()
		if err != nil {
			cancel()
			return nil, err
		}
		return &ServerStream{cs, method.GetOutputType(), s.mf}, nil
	}
}
func (s Stub) InvokeRpcClientStream(ctx context.Context, method *desc.MethodDescriptor, opts ...grpc.CallOption) (*ClientStream, error) {
	if !method.IsClientStreaming() || method.IsServerStreaming() {
		return nil, fmt.Errorf("InvokeRpcClientStream is for client-streaming methods; %q is %s", method.GetFullyQualifiedName(), methodType(method))
	}
	ctx, cancel := context.WithCancel(ctx)
	sd := grpc.StreamDesc{
		StreamName:    method.GetName(),
		ServerStreams: method.IsServerStreaming(),
		ClientStreams: method.IsClientStreaming(),
	}
	if cs, err := s.channel.NewStream(ctx, &sd, requestMethod(method), opts...); err != nil {
		return nil, err
	} else {
		return &ClientStream{cs, method, s.mf, cancel}, nil
	}
}
func (s Stub) InvokeRpcBidiStream(ctx context.Context, method *desc.MethodDescriptor, opts ...grpc.CallOption) (*BidiStream, error) {
	if !method.IsClientStreaming() || !method.IsServerStreaming() {
		return nil, fmt.Errorf("InvokeRpcBidiStream is for bidi-streaming methods; %q is %s", method.GetFullyQualifiedName(), methodType(method))
	}
	sd := grpc.StreamDesc{
		StreamName:    method.GetName(),
		ServerStreams: method.IsServerStreaming(),
		ClientStreams: method.IsClientStreaming(),
	}
	if cs, err := s.channel.NewStream(ctx, &sd, requestMethod(method), opts...); err != nil {
		return nil, err
	} else {
		return &BidiStream{cs, method.GetInputType(), method.GetOutputType(), s.mf}, nil
	}
}
func methodType(md *desc.MethodDescriptor) string {
	if md.IsClientStreaming() && md.IsServerStreaming() {
		return "bidi-streaming"
	} else if md.IsClientStreaming() {
		return "client-streaming"
	} else if md.IsServerStreaming() {
		return "server-streaming"
	} else {
		return "unary"
	}
}
func checkMessageType(md *desc.MessageDescriptor, msg proto.Message) error {
	var typeName string
	if dm, ok := msg.(*dynamic.Message); ok {
		typeName = dm.GetMessageDescriptor().GetFullyQualifiedName()
	} else {
		typeName = proto.MessageName(msg)
	}
	if typeName != md.GetFullyQualifiedName() {
		return fmt.Errorf("expecting message of type %s; got %s", md.GetFullyQualifiedName(), typeName)
	}
	return nil
}
type ServerStream struct {
	stream   grpc.ClientStream
	respType *desc.MessageDescriptor
	mf       *dynamic.MessageFactory
}
func (s *ServerStream) Header() (metadata.MD, error) {
	return s.stream.Header()
}
func (s *ServerStream) Trailer() metadata.MD {
	return s.stream.Trailer()
}