File: csi_write.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 (152 lines) | stat: -rw-r--r-- 4,249 bytes parent folder | download | duplicates (2)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright ©2015 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 csi

import (
	"encoding/binary"
	"fmt"
	"io"

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

// WriteTo writes the CSI index to the given io.Writer. Note that
// the csi specification states that the index is stored as BGZF, but
// WriteTo does not perform compression.
func WriteTo(w io.Writer, idx *Index) error {
	idx.sort()
	err := binary.Write(w, binary.LittleEndian, csiMagic)
	if err != nil {
		return err
	}
	_, err = w.Write([]byte{idx.Version})
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.LittleEndian, int32(idx.minShift))
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.LittleEndian, int32(idx.depth))
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.LittleEndian, int32(len(idx.Auxilliary)))
	if err != nil {
		return err
	}
	_, err = w.Write(idx.Auxilliary)
	if err != nil {
		return err
	}
	binLimit := uint32(((1 << ((idx.depth + 1) * nextBinShift)) - 1) / 7)
	err = writeIndices(w, idx.Version, idx.refs, binLimit)
	if err != nil {
		return err
	}
	if idx.unmapped != nil {
		err = binary.Write(w, binary.LittleEndian, idx.unmapped)
	}
	return err
}

func writeIndices(w io.Writer, version byte, idx []refIndex, binLimit uint32) error {
	err := binary.Write(w, binary.LittleEndian, int32(len(idx)))
	if err != nil {
		return err
	}
	for i := range idx {
		err = writeBins(w, version, idx[i].bins, idx[i].stats, binLimit)
		if err != nil {
			return err
		}
	}
	return nil
}

func writeBins(w io.Writer, version byte, bins []bin, stats *index.ReferenceStats, binLimit uint32) error {
	n := int32(len(bins))
	if stats != nil {
		n++
	}
	err := binary.Write(w, binary.LittleEndian, &n)
	if err != nil {
		return err
	}
	for _, b := range bins {
		err = binary.Write(w, binary.LittleEndian, b.bin)
		if err != nil {
			return fmt.Errorf("csi: failed to write bin number: %v", err)
		}
		err = binary.Write(w, binary.LittleEndian, vOffset(b.left))
		if err != nil {
			return fmt.Errorf("csi: failed to write left virtual offset: %v", err)
		}
		if version == 0x2 {
			err = binary.Write(w, binary.LittleEndian, b.records)
			if err != nil {
				return fmt.Errorf("csi: failed to write record count: %v", err)
			}
		}
		err = writeChunks(w, b.chunks)
		if err != nil {
			return err
		}
	}
	if stats != nil {
		return writeStats(w, version, stats, binLimit)
	}
	return nil
}

func writeChunks(w io.Writer, chunks []bgzf.Chunk) error {
	err := binary.Write(w, binary.LittleEndian, int32(len(chunks)))
	if err != nil {
		return fmt.Errorf("csi: failed to write bin count: %v", err)
	}
	for _, c := range chunks {
		err = binary.Write(w, binary.LittleEndian, vOffset(c.Begin))
		if err != nil {
			return fmt.Errorf("csi: failed to write chunk begin virtual offset: %v", err)
		}
		err = binary.Write(w, binary.LittleEndian, vOffset(c.End))
		if err != nil {
			return fmt.Errorf("csi: failed to write chunk end virtual offset: %v", err)
		}
	}
	return nil
}

func writeStats(w io.Writer, version byte, stats *index.ReferenceStats, binLimit uint32) error {
	var err error
	statsDummyBin := binLimit + 1
	switch version {
	case 0x1:
		err = binary.Write(w, binary.LittleEndian, [4]uint32{statsDummyBin, 0, 0, 2})
	case 0x2:
		err = binary.Write(w, binary.LittleEndian, [6]uint32{statsDummyBin, 0, 0, 0, 0, 2})
	}
	if err != nil {
		return fmt.Errorf("csi: failed to write stats bin header: %v", err)
	}
	err = binary.Write(w, binary.LittleEndian, vOffset(stats.Chunk.Begin))
	if err != nil {
		return fmt.Errorf("csi: failed to write index stats chunk begin virtual offset: %v", err)
	}
	err = binary.Write(w, binary.LittleEndian, vOffset(stats.Chunk.End))
	if err != nil {
		return fmt.Errorf("csi: failed to write index stats chunk end virtual offset: %v", err)
	}
	err = binary.Write(w, binary.LittleEndian, stats.Mapped)
	if err != nil {
		return fmt.Errorf("csi: failed to write index stats mapped count: %v", err)
	}
	err = binary.Write(w, binary.LittleEndian, stats.Unmapped)
	if err != nil {
		return fmt.Errorf("csi: failed to write index stats unmapped count: %v", err)
	}
	return nil
}