File: index.go

package info (click to toggle)
golang-github-biogo-hts 1.4.4%2Bdfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,740 kB
  • sloc: makefile: 3
file content (127 lines) | stat: -rw-r--r-- 3,104 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright ©2014 The bíogo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bam

import (
	"encoding/binary"
	"errors"
	"io"

	"github.com/biogo/hts/bgzf"
	"github.com/biogo/hts/bgzf/index"
	"github.com/biogo/hts/internal"
	"github.com/biogo/hts/sam"
)

// Index is a BAI index.
type Index struct {
	idx internal.Index

	// MergeStrategy is used to determine the
	// the merge strategy used to prepare the
	// slice of chunks returned by Chunks.
	// If MergeStrategy is nil, index.MergeStrategy
	// is used.
	MergeStrategy index.MergeStrategy
}

// NumRefs returns the number of references in the index.
func (i *Index) NumRefs() int {
	return len(i.idx.Refs)
}

// ReferenceStats returns the index statistics for the given reference and true
// if the statistics are valid.
func (i *Index) ReferenceStats(id int) (stats index.ReferenceStats, ok bool) {
	s := i.idx.Refs[id].Stats
	if s == nil {
		return index.ReferenceStats{}, false
	}
	return index.ReferenceStats(*s), true
}

// Unmapped returns the number of unmapped reads and true if the count is valid.
func (i *Index) Unmapped() (n uint64, ok bool) {
	if i.idx.Unmapped == nil {
		return 0, false
	}
	return *i.idx.Unmapped, true
}

// Add records the SAM record as having being located at the given chunk.
func (i *Index) Add(r *sam.Record, c bgzf.Chunk) error {
	return i.idx.Add(r, uint32(r.Bin()), c, isPlaced(r), isMapped(r))
}

func isPlaced(r *sam.Record) bool {
	return r.Ref != nil && r.Pos != -1
}

func isMapped(r *sam.Record) bool {
	return r.Flags&sam.Unmapped == 0
}

// Chunks returns a []bgzf.Chunk that corresponds to the given genomic interval.
func (i *Index) Chunks(r *sam.Reference, beg, end int) ([]bgzf.Chunk, error) {
	chunks, err := i.idx.Chunks(r.ID(), beg, end)
	if err != nil {
		return nil, err
	}
	if i.MergeStrategy == nil {
		return index.Adjacent(chunks), nil
	}
	return i.MergeStrategy(chunks), nil
}

// MergeChunks applies the given MergeStrategy to all bins in the Index.
func (i *Index) MergeChunks(s index.MergeStrategy) {
	i.idx.MergeChunks(s)
}

var baiMagic = [4]byte{'B', 'A', 'I', 0x1}

// ReadIndex reads the BAI Index from the given io.Reader.
func ReadIndex(r io.Reader) (*Index, error) {
	var (
		idx   Index
		magic [4]byte
		err   error
	)
	err = binary.Read(r, binary.LittleEndian, &magic)
	if err != nil {
		return nil, err
	}
	if magic != baiMagic {
		return nil, errors.New("bam: magic number mismatch")
	}

	var n int32
	err = binary.Read(r, binary.LittleEndian, &n)
	if err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, nil
	}
	idx.idx, err = internal.ReadIndex(r, n, "bam")
	if err != nil {
		return nil, err
	}
	return &idx, nil
}

// WriteIndex writes the Index to the given io.Writer.
func WriteIndex(w io.Writer, idx *Index) error {
	err := binary.Write(w, binary.LittleEndian, baiMagic)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.LittleEndian, int32(len(idx.idx.Refs)))
	if err != nil {
		return err
	}
	return internal.WriteIndex(w, &idx.idx, "bam")
}