func prefixSuccessor(prefix string) string {
	if prefix == "" {
		return ""  
	}
	n := len(prefix)
	for n--; n >= 0 && prefix[n] == '\xff'; n-- {
	}
	if n == -1 {
		return ""
	}
	ans := []byte(prefix[:n])
	ans = append(ans, prefix[n]+1)
	return string(ans)
}
prefixSuccessor returns the lexically smallest string greater than the
prefix, if it exists, or "" otherwise.  In either case, it is the string
needed for the Limit of a RowRange.
package bigtable
import (
	"fmt"
	"io"
	"strconv"
	"time"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/cloud"
	btdpb "google.golang.org/cloud/bigtable/internal/data_proto"
	btspb "google.golang.org/cloud/bigtable/internal/service_proto"
	"google.golang.org/cloud/internal/transport"
	"google.golang.org/grpc"
)
const prodAddr = "bigtable.googleapis.com:443"
type Client struct {
	conn   *grpc.ClientConn
	client btspb.BigtableServiceClient
	project, zone, cluster string
}
func NewClient(ctx context.Context, project, zone, cluster string, opts ...cloud.ClientOption) (*Client, error) {
	o := []cloud.ClientOption{
		cloud.WithEndpoint(prodAddr),
		cloud.WithScopes(Scope),
		cloud.WithUserAgent(clientUserAgent),
	}
	o = append(o, opts...)
	conn, err := transport.DialGRPC(ctx, o...)
	if err != nil {
		return nil, fmt.Errorf("dialing: %v", err)
	}
	return &Client{
		conn:   conn,
		client: btspb.NewBigtableServiceClient(conn),
		project: project,
		zone:    zone,
		cluster: cluster,
	}, nil
}
func (c *Client) Close() {
	c.conn.Close()
}
func (c *Client) fullTableName(table string) string {
	return fmt.Sprintf("projects/%s/zones/%s/clusters/%s/tables/%s", c.project, c.zone, c.cluster, table)
}
type Table struct {
	c     *Client
	table string
}
func (c *Client) Open(table string) *Table {
	return &Table{
		c:     c,
		table: table,
	}
}
func (t *Table) ReadRows(ctx context.Context, arg RowRange, f func(Row) bool, opts ...ReadOption) error {
	req := &btspb.ReadRowsRequest{
		TableName: t.c.fullTableName(t.table),
		Target:    &btspb.ReadRowsRequest_RowRange{arg.proto()},
	}
	for _, opt := range opts {
		opt.set(req)
	}
	ctx, cancel := context.WithCancel(ctx)  
	defer cancel()
	stream, err := t.c.client.ReadRows(ctx, req)
	if err != nil {
		return err
	}
	cr := new(chunkReader)
	for {
		res, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		if row := cr.process(res); row != nil {
			if !f(row) {
				cancel()
				for {
					if _, err := stream.Recv(); err != nil {
						return nil
					}
				}
			}
		}
	}
	return nil
}
func (t *Table) ReadRow(ctx context.Context, row string, opts ...ReadOption) (Row, error) {
	var r Row
	err := t.ReadRows(ctx, SingleRow(row), func(rr Row) bool {
		r = rr
		return true
	}, opts...)
	return r, err
}
type chunkReader struct {
	partial map[string]Row  
}
func (cr *chunkReader) process(rrr *btspb.ReadRowsResponse) Row {
	if cr.partial == nil {
		cr.partial = make(map[string]Row)
	}
	row := string(rrr.RowKey)
	r := cr.partial[row]
	if r == nil {
		r = make(Row)
		cr.partial[row] = r
	}
	for _, chunk := range rrr.Chunks {
		switch c := chunk.Chunk.(type) {
		case *btspb.ReadRowsResponse_Chunk_ResetRow:
			r = make(Row)
			cr.partial[row] = r
			continue
		case *btspb.ReadRowsResponse_Chunk_CommitRow:
			delete(cr.partial, row)
			if len(r) == 0 {
				continue
			}
			return r  
		case *btspb.ReadRowsResponse_Chunk_RowContents:
			decodeFamilyProto(r, row, c.RowContents)
		}
	}
	return nil
}
func decodeFamilyProto(r Row, row string, f *btdpb.Family) {
	fam := f.Name  
	for _, col := range f.Columns {
		for _, cell := range col.Cells {
			ri := ReadItem{
				Row:       row,
				Column:    fmt.Sprintf("%s:%s", fam, col.Qualifier),
				Timestamp: Timestamp(cell.TimestampMicros),
				Value:     cell.Value,
			}
			r[fam] = append(r[fam], ri)
		}
	}
}
type RowRange struct {
	start string
	limit string
}
func NewRange(begin, end string) RowRange {
	return RowRange{
		start: begin,
		limit: end,
	}
}
func (r RowRange) Unbounded() bool {
	return r.limit == ""
}
func (r RowRange) Contains(row string) bool {
	return r.start <= row && (r.limit == "" || r.limit > row)
}
func (r RowRange) String() string {
	a := strconv.Quote(r.start)
	if r.Unbounded() {
		return fmt.Sprintf("[%s,∞)", a)
	}
	return fmt.Sprintf("[%s,%q)", a, r.limit)
}
func (r RowRange) proto() *btdpb.RowRange {
	if r.Unbounded() {
		return &btdpb.RowRange{StartKey: []byte(r.start)}
	}
	return &btdpb.RowRange{
		StartKey: []byte(r.start),
		EndKey:   []byte(r.limit),
	}
}
func SingleRow(row string) RowRange {
	return RowRange{
		start: row,
		limit: row + "\x00",
	}
}
func PrefixRange(prefix string) RowRange {
	return RowRange{
		start: prefix,
		limit: prefixSuccessor(prefix),
	}
}
func InfiniteRange(start string) RowRange {
	return RowRange{
		start: start,
		limit: "",
	}
}