func (s *AdjacentBAMShard) Scan() bool {
	if err := s.errors.Err(); err != nil {
		s.pair = Pair{
			Err: fmt.Errorf("error while reading shard %d: stopped reading shard due to read error in other worker: %s", s.ShardIdx, err),
		}
		return true
	}
	defer func() {
		if s.pair.Err != nil {
			s.errors.Set(s.pair.Err)
		}
	}()
	record := s.recs.getRecord()
	if record == nil {
		return false
	}
	mate := s.recs.getRecord()
	if mate == nil {
		s.pair = Pair{
			Err: fmt.Errorf("error while reading shard %d: could not find mate for record %s", s.ShardIdx, record),
		}
		return true
	}
	if record.Pos != mate.MatePos || record.MatePos != mate.Pos {
		s.pair = Pair{
			Err: fmt.Errorf("shard %d: records %s and %s do not have matching pos/mate pos", s.ShardIdx, record, mate),
		}
		return true
	}
	switch {
	case IsRead1(record) && IsRead2(mate):
		s.pair = Pair{R1: record, R2: mate}
	case IsRead1(mate) && IsRead2(record):
		s.pair = Pair{R1: mate, R2: record}
	default:
		s.pair = Pair{
			Err: fmt.Errorf("shard %d: records %s and %s are not a valid R1/R2 pair", s.ShardIdx, record, mate),
		}
	}
	return true
}
Scan reads the next record. It returns true if a record has been read
or if an error is encountered, and false on end of data stream.
package bam
import (
	"context"
	"fmt"
	"io"
	"github.com/grailbio/base/errors"
	"github.com/grailbio/hts/bam"
	"github.com/grailbio/hts/sam"
)
type Pair struct {
	R1  *sam.Record
	R2  *sam.Record
	Err error
}
type AdjacentShardedBAMReader struct {
	shardc chan *AdjacentBAMShard
	header *sam.Header
	errors *errors.Once
}
func NewAdjacentShardedBAMReader(ctx context.Context, r io.Reader, recordsPerShard int, queueSize int) (*AdjacentShardedBAMReader, error) {
	if recordsPerShard%2 != 0 {
		panic("shards must have an even number of records: each record must belong to a pair")
	}
	br, err := bam.NewReader(r, 1)
	if err != nil {
		return nil, err
	}
	sbr := &AdjacentShardedBAMReader{
		shardc: make(chan *AdjacentBAMShard, queueSize),
		errors: new(errors.Once),
		header: br.Header(),
	}
	go func() {
		defer func() {
			close(sbr.shardc)
			_ = br.Close()
		}()
		var shardIdx int
		shard := &AdjacentBAMShard{
			ShardIdx: shardIdx,
			recs:     newRecBuffer(recordsPerShard),
			errors:   sbr.errors,
		}
		for {
			select {
			case <-ctx.Done():
				sbr.errors.Set(fmt.Errorf("error while reading BAM file: %s", ctx.Err()))
				return
			default:
			}
			if sbr.errors.Err() != nil {
				return
			}
			rec, err := br.Read()
			if rec == nil {
				if err != io.EOF {
					sbr.errors.Set(fmt.Errorf("error while reading BAM file: %s", err))
					return
				}
				if shard.recs.numRecords() > 0 {
					sbr.shardc <- shard
				}
				return
			}
			shard.recs.addRecord(rec)
			if shard.recs.numRecords() >= recordsPerShard {
				sbr.shardc <- shard
				shardIdx++
				shard = &AdjacentBAMShard{
					ShardIdx: shardIdx,
					recs:     newRecBuffer(recordsPerShard),
					errors:   sbr.errors,
				}
			}
		}
	}()
	return sbr, nil
}
func (r *AdjacentShardedBAMReader) Header() *sam.Header {
	return r.header
}
func (r *AdjacentShardedBAMReader) GetShard() *AdjacentBAMShard {
	s, ok := <-r.shardc
	if !ok {
		return nil
	}
	return s
}
type AdjacentBAMShard struct {
	ShardIdx int
	recs recBuffer
	pair Pair
	errors *errors.Once
}
func (s *AdjacentBAMShard) Record() Pair { return s.pair }