htslib 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +79 -49
- data/TUTORIAL.md +9 -20
- data/ext/htslib_native/extconf.rb +41 -0
- data/ext/htslib_native/htslib_native.h +11 -0
- data/ext/htslib_native/htslib_native_ext.c +48 -0
- data/ext/htslib_native/native_bam.c +1108 -0
- data/ext/htslib_native/native_bcf.c +369 -0
- data/ext/htslib_native/native_faidx.c +155 -0
- data/ext/htslib_native/native_tabix.c +246 -0
- data/lib/hts/bam/auxi.rb +87 -342
- data/lib/hts/bam/base_mod.rb +37 -73
- data/lib/hts/bam/cigar.rb +9 -55
- data/lib/hts/bam/flag.rb +19 -27
- data/lib/hts/bam/header.rb +29 -56
- data/lib/hts/bam/mpileup.rb +158 -132
- data/lib/hts/bam/pileup.rb +120 -145
- data/lib/hts/bam/record.rb +233 -270
- data/lib/hts/bam.rb +102 -42
- data/lib/hts/bcf/errors.rb +1 -0
- data/lib/hts/bcf/format.rb +278 -379
- data/lib/hts/bcf/header.rb +38 -122
- data/lib/hts/bcf/header_record.rb +9 -35
- data/lib/hts/bcf/info.rb +72 -320
- data/lib/hts/bcf/record.rb +61 -102
- data/lib/hts/bcf.rb +149 -323
- data/lib/hts/faidx.rb +28 -87
- data/lib/hts/hts.rb +6 -94
- data/lib/hts/native.rb +13 -0
- data/lib/hts/tabix.rb +93 -48
- data/lib/hts/version.rb +1 -1
- data/lib/htslib.rb +6 -52
- metadata +13 -64
- data/lib/hts/ffi_ext/README.md +0 -8
- data/lib/hts/ffi_ext/pointer.rb +0 -18
- data/lib/hts/ffi_ext/struct.rb +0 -45
- data/lib/hts/libhts/bgzf.rb +0 -199
- data/lib/hts/libhts/constants.rb +0 -658
- data/lib/hts/libhts/cram.rb +0 -471
- data/lib/hts/libhts/fai.rb +0 -146
- data/lib/hts/libhts/hfile.rb +0 -121
- data/lib/hts/libhts/hts.rb +0 -477
- data/lib/hts/libhts/kfunc.rb +0 -38
- data/lib/hts/libhts/sam.rb +0 -760
- data/lib/hts/libhts/sam_funcs.rb +0 -155
- data/lib/hts/libhts/tbx.rb +0 -94
- data/lib/hts/libhts/tbx_funcs.rb +0 -36
- data/lib/hts/libhts/thread_pool.rb +0 -139
- data/lib/hts/libhts/vcf.rb +0 -567
- data/lib/hts/libhts/vcf_funcs.rb +0 -366
- data/lib/hts/libhts.rb +0 -47
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#include "htslib_native.h"
|
|
2
|
+
|
|
3
|
+
#include <htslib/hts.h>
|
|
4
|
+
#include <htslib/kstring.h>
|
|
5
|
+
#include <htslib/tbx.h>
|
|
6
|
+
#include <stdlib.h>
|
|
7
|
+
|
|
8
|
+
typedef struct {
|
|
9
|
+
htsFile *file;
|
|
10
|
+
tbx_t *index;
|
|
11
|
+
VALUE path;
|
|
12
|
+
int active_queries;
|
|
13
|
+
} ruby_tabix_t;
|
|
14
|
+
|
|
15
|
+
typedef struct {
|
|
16
|
+
ruby_tabix_t *handle;
|
|
17
|
+
hts_itr_t *iterator;
|
|
18
|
+
kstring_t line;
|
|
19
|
+
} tabix_query_t;
|
|
20
|
+
|
|
21
|
+
static VALUE cNativeTabix;
|
|
22
|
+
|
|
23
|
+
static void ruby_tabix_mark(void *pointer)
|
|
24
|
+
{
|
|
25
|
+
ruby_tabix_t *handle = pointer;
|
|
26
|
+
rb_gc_mark_movable(handle->path);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static void ruby_tabix_compact(void *pointer)
|
|
30
|
+
{
|
|
31
|
+
ruby_tabix_t *handle = pointer;
|
|
32
|
+
handle->path = rb_gc_location(handle->path);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static void ruby_tabix_free(void *pointer)
|
|
36
|
+
{
|
|
37
|
+
ruby_tabix_t *handle = pointer;
|
|
38
|
+
if (handle->index != NULL) tbx_destroy(handle->index);
|
|
39
|
+
if (handle->file != NULL) hts_close(handle->file);
|
|
40
|
+
xfree(handle);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static size_t ruby_tabix_size(const void *pointer)
|
|
44
|
+
{
|
|
45
|
+
return pointer == NULL ? 0 : sizeof(ruby_tabix_t);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static const rb_data_type_t ruby_tabix_type = {
|
|
49
|
+
.wrap_struct_name = "HTS::Native::TabixHandle",
|
|
50
|
+
.function = {
|
|
51
|
+
.dmark = ruby_tabix_mark,
|
|
52
|
+
.dfree = ruby_tabix_free,
|
|
53
|
+
.dsize = ruby_tabix_size,
|
|
54
|
+
.dcompact = ruby_tabix_compact,
|
|
55
|
+
},
|
|
56
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
static ruby_tabix_t *get_tabix(VALUE self, int allow_closed)
|
|
60
|
+
{
|
|
61
|
+
ruby_tabix_t *handle;
|
|
62
|
+
TypedData_Get_Struct(self, ruby_tabix_t, &ruby_tabix_type, handle);
|
|
63
|
+
if (!allow_closed && handle->file == NULL) rb_raise(rb_eIOError, "closed Tabix");
|
|
64
|
+
return handle;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static VALUE native_tabix_open(VALUE klass, VALUE path_value)
|
|
68
|
+
{
|
|
69
|
+
ruby_tabix_t *handle;
|
|
70
|
+
VALUE object = TypedData_Make_Struct(klass, ruby_tabix_t, &ruby_tabix_type, handle);
|
|
71
|
+
handle->index = NULL;
|
|
72
|
+
handle->active_queries = 0;
|
|
73
|
+
handle->path = rb_str_dup(StringValue(path_value));
|
|
74
|
+
RB_OBJ_WRITE(object, &handle->path, handle->path);
|
|
75
|
+
handle->file = hts_open(StringValueCStr(handle->path), "r");
|
|
76
|
+
if (handle->file == NULL) rb_syserr_fail_str(ENOENT, path_value);
|
|
77
|
+
return object;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static VALUE native_tabix_close(VALUE self)
|
|
81
|
+
{
|
|
82
|
+
ruby_tabix_t *handle = get_tabix(self, 1);
|
|
83
|
+
if (handle->active_queries > 0) rb_raise(rb_eIOError, "cannot close Tabix during an active query");
|
|
84
|
+
if (handle->index != NULL) {
|
|
85
|
+
tbx_destroy(handle->index);
|
|
86
|
+
handle->index = NULL;
|
|
87
|
+
}
|
|
88
|
+
if (handle->file != NULL) {
|
|
89
|
+
hts_close(handle->file);
|
|
90
|
+
handle->file = NULL;
|
|
91
|
+
}
|
|
92
|
+
return Qnil;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static VALUE native_tabix_closed(VALUE self)
|
|
96
|
+
{
|
|
97
|
+
return get_tabix(self, 1)->file == NULL ? Qtrue : Qfalse;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static VALUE native_tabix_set_threads(VALUE self, VALUE count_value)
|
|
101
|
+
{
|
|
102
|
+
ruby_tabix_t *handle = get_tabix(self, 0);
|
|
103
|
+
return INT2NUM(hts_set_threads(handle->file, NUM2INT(count_value)));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static VALUE native_tabix_format(VALUE self)
|
|
107
|
+
{
|
|
108
|
+
ruby_tabix_t *handle = get_tabix(self, 0);
|
|
109
|
+
const htsFormat *format = hts_get_format(handle->file);
|
|
110
|
+
if (format == NULL) return Qnil;
|
|
111
|
+
switch (format->format) {
|
|
112
|
+
case vcf: return rb_str_new_cstr("vcf");
|
|
113
|
+
case bcf: return rb_str_new_cstr("bcf");
|
|
114
|
+
case sam: return rb_str_new_cstr("sam");
|
|
115
|
+
case bam: return rb_str_new_cstr("bam");
|
|
116
|
+
case cram: return rb_str_new_cstr("cram");
|
|
117
|
+
case bed: return rb_str_new_cstr("bed");
|
|
118
|
+
default: return rb_str_new_cstr("unknown_format");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static VALUE native_tabix_format_version(VALUE self)
|
|
123
|
+
{
|
|
124
|
+
ruby_tabix_t *handle = get_tabix(self, 0);
|
|
125
|
+
const htsFormat *format = hts_get_format(handle->file);
|
|
126
|
+
if (format == NULL) return Qnil;
|
|
127
|
+
if (format->version.minor == -1) return rb_sprintf("%d", format->version.major);
|
|
128
|
+
return rb_sprintf("%d.%d", format->version.major, format->version.minor);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static VALUE native_tabix_build(VALUE klass, VALUE path_value, VALUE index_value, VALUE shift_value)
|
|
132
|
+
{
|
|
133
|
+
const char *path = StringValueCStr(path_value);
|
|
134
|
+
int shift = NUM2INT(shift_value), result;
|
|
135
|
+
if (NIL_P(index_value)) {
|
|
136
|
+
result = tbx_index_build(path, shift, &tbx_conf_vcf);
|
|
137
|
+
} else {
|
|
138
|
+
result = tbx_index_build2(path, StringValueCStr(index_value), shift, &tbx_conf_vcf);
|
|
139
|
+
}
|
|
140
|
+
return INT2NUM(result);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
static VALUE native_tabix_load_index(VALUE self, VALUE index_value)
|
|
144
|
+
{
|
|
145
|
+
ruby_tabix_t *handle = get_tabix(self, 0);
|
|
146
|
+
if (handle->index != NULL) {
|
|
147
|
+
tbx_destroy(handle->index);
|
|
148
|
+
handle->index = NULL;
|
|
149
|
+
}
|
|
150
|
+
handle->index = NIL_P(index_value)
|
|
151
|
+
? tbx_index_load3(StringValueCStr(handle->path), NULL, HTS_IDX_SAVE_REMOTE)
|
|
152
|
+
: tbx_index_load2(StringValueCStr(handle->path), StringValueCStr(index_value));
|
|
153
|
+
return handle->index == NULL ? Qfalse : Qtrue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static VALUE native_tabix_index_loaded(VALUE self)
|
|
157
|
+
{
|
|
158
|
+
return get_tabix(self, 0)->index == NULL ? Qfalse : Qtrue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static VALUE native_tabix_name2id(VALUE self, VALUE name_value)
|
|
162
|
+
{
|
|
163
|
+
ruby_tabix_t *handle = get_tabix(self, 0);
|
|
164
|
+
if (handle->index == NULL) rb_raise(rb_eRuntimeError, "index file is required");
|
|
165
|
+
return INT2NUM(tbx_name2id(handle->index, StringValueCStr(name_value)));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static VALUE native_tabix_seqnames(VALUE self)
|
|
169
|
+
{
|
|
170
|
+
ruby_tabix_t *handle = get_tabix(self, 0);
|
|
171
|
+
const char **names;
|
|
172
|
+
int count = 0, index;
|
|
173
|
+
VALUE result;
|
|
174
|
+
if (handle->index == NULL) rb_raise(rb_eRuntimeError, "index file is required");
|
|
175
|
+
names = tbx_seqnames(handle->index, &count);
|
|
176
|
+
result = rb_ary_new_capa(count);
|
|
177
|
+
for (index = 0; index < count; index++) rb_ary_push(result, rb_str_new_cstr(names[index]));
|
|
178
|
+
free(names);
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static VALUE tabix_query_body(VALUE data_value)
|
|
183
|
+
{
|
|
184
|
+
tabix_query_t *query = (tabix_query_t *)data_value;
|
|
185
|
+
int result;
|
|
186
|
+
while ((result = tbx_itr_next(query->handle->file, query->handle->index,
|
|
187
|
+
query->iterator, &query->line)) >= 0) {
|
|
188
|
+
rb_yield(rb_str_new(query->line.s, query->line.l));
|
|
189
|
+
}
|
|
190
|
+
if (result < -1) rb_raise(rb_eRuntimeError, "failed while reading Tabix query");
|
|
191
|
+
return Qnil;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
static VALUE tabix_query_cleanup(VALUE data_value)
|
|
195
|
+
{
|
|
196
|
+
tabix_query_t *query = (tabix_query_t *)data_value;
|
|
197
|
+
if (query->iterator != NULL) hts_itr_destroy(query->iterator);
|
|
198
|
+
free(query->line.s);
|
|
199
|
+
query->handle->active_queries--;
|
|
200
|
+
return Qnil;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static VALUE native_tabix_query_region(VALUE self, VALUE region_value)
|
|
204
|
+
{
|
|
205
|
+
ruby_tabix_t *handle = get_tabix(self, 0);
|
|
206
|
+
tabix_query_t query = { .handle = handle, .iterator = NULL, .line = KS_INITIALIZE };
|
|
207
|
+
if (!rb_block_given_p()) rb_raise(rb_eArgError, "block is required");
|
|
208
|
+
if (handle->index == NULL) rb_raise(rb_eRuntimeError, "index file is required");
|
|
209
|
+
query.iterator = tbx_itr_querys(handle->index, StringValueCStr(region_value));
|
|
210
|
+
if (query.iterator == NULL) rb_raise(rb_eRuntimeError, "failed to query region");
|
|
211
|
+
handle->active_queries++;
|
|
212
|
+
rb_ensure(tabix_query_body, (VALUE)&query, tabix_query_cleanup, (VALUE)&query);
|
|
213
|
+
return self;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
static VALUE native_tabix_query_interval(VALUE self, VALUE id_value, VALUE start_value, VALUE end_value)
|
|
217
|
+
{
|
|
218
|
+
ruby_tabix_t *handle = get_tabix(self, 0);
|
|
219
|
+
tabix_query_t query = { .handle = handle, .iterator = NULL, .line = KS_INITIALIZE };
|
|
220
|
+
if (!rb_block_given_p()) rb_raise(rb_eArgError, "block is required");
|
|
221
|
+
if (handle->index == NULL) rb_raise(rb_eRuntimeError, "index file is required");
|
|
222
|
+
query.iterator = tbx_itr_queryi(handle->index, NUM2INT(id_value), NUM2LL(start_value), NUM2LL(end_value));
|
|
223
|
+
if (query.iterator == NULL) rb_raise(rb_eRuntimeError, "failed to query region");
|
|
224
|
+
handle->active_queries++;
|
|
225
|
+
rb_ensure(tabix_query_body, (VALUE)&query, tabix_query_cleanup, (VALUE)&query);
|
|
226
|
+
return self;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
void Init_htslib_native_tabix(VALUE native)
|
|
230
|
+
{
|
|
231
|
+
cNativeTabix = rb_define_class_under(native, "TabixHandle", rb_cObject);
|
|
232
|
+
rb_undef_alloc_func(cNativeTabix);
|
|
233
|
+
rb_define_singleton_method(cNativeTabix, "open", native_tabix_open, 1);
|
|
234
|
+
rb_define_singleton_method(cNativeTabix, "build", native_tabix_build, 3);
|
|
235
|
+
rb_define_method(cNativeTabix, "close", native_tabix_close, 0);
|
|
236
|
+
rb_define_method(cNativeTabix, "closed?", native_tabix_closed, 0);
|
|
237
|
+
rb_define_method(cNativeTabix, "set_threads", native_tabix_set_threads, 1);
|
|
238
|
+
rb_define_method(cNativeTabix, "file_format", native_tabix_format, 0);
|
|
239
|
+
rb_define_method(cNativeTabix, "file_format_version", native_tabix_format_version, 0);
|
|
240
|
+
rb_define_method(cNativeTabix, "load_index", native_tabix_load_index, 1);
|
|
241
|
+
rb_define_method(cNativeTabix, "index_loaded?", native_tabix_index_loaded, 0);
|
|
242
|
+
rb_define_method(cNativeTabix, "name2id", native_tabix_name2id, 1);
|
|
243
|
+
rb_define_method(cNativeTabix, "seqnames", native_tabix_seqnames, 0);
|
|
244
|
+
rb_define_method(cNativeTabix, "query_region", native_tabix_query_region, 1);
|
|
245
|
+
rb_define_method(cNativeTabix, "query_interval", native_tabix_query_interval, 3);
|
|
246
|
+
}
|