///|
pub(all) enum VariantClass {
Empty
SNV
MNV
Insertion
Deletion
Mixed
Symbolic
} derive(Debug, Eq)
///|
pub fn record_variant_class(record : VcfRecord) -> VariantClass {
if record.alt_alleles.length() == 0 {
VariantClass::Empty
} else if record.alt_alleles.any(is_symbolic_record_alt) {
VariantClass::Symbolic
} else {
let mut first : VariantClass? = None
for alt in record.alt_alleles {
let current = classify_allele_pair(record.ref_allele, alt)
match first {
None => first = Some(current)
Some(previous) if previous != current => return VariantClass::Mixed
Some(_) => ()
}
}
match first {
Some(value) => value
None => VariantClass::Empty
}
}
}
///|
fn classify_allele_pair(ref_allele : String, alt : String) -> VariantClass {
if ref_allele.length() == 1 && alt.length() == 1 {
VariantClass::SNV
} else if ref_allele.length() == alt.length() {
VariantClass::MNV
} else if ref_allele.length() < alt.length() {
VariantClass::Insertion
} else {
VariantClass::Deletion
}
}
///|
fn is_symbolic_record_alt(alt : String) -> Bool {
alt.has_prefix("<") || alt == "*"
}
///|
pub fn record_alt_count(record : VcfRecord) -> Int {
record.alt_alleles.length()
}
///|
pub fn record_is_snv(record : VcfRecord) -> Bool {
record_variant_class(record) == VariantClass::SNV
}
///|
pub fn record_is_indel(record : VcfRecord) -> Bool {
let class = record_variant_class(record)
class == VariantClass::Insertion || class == VariantClass::Deletion
}
///|
pub fn record_has_info(record : VcfRecord, key : String) -> Bool {
for pair in record.info {
if pair.0 == key {
return true
}
}
false
}
///|
pub fn record_info_value(record : VcfRecord, key : String) -> VcfValue? {
for pair in record.info {
if pair.0 == key {
return Some(pair.1)
}
}
None
}
///|
pub fn record_info_int(record : VcfRecord, key : String) -> Int? {
match record_info_value(record, key) {
Some(VcfValue::Integer(value)) => Some(value)
Some(VcfValue::List(values)) if values.length() > 0 =>
match values[0] {
VcfValue::Integer(value) => Some(value)
_ => None
}
_ => None
}
}
///|
pub fn record_info_float(record : VcfRecord, key : String) -> Double? {
match record_info_value(record, key) {
Some(VcfValue::Float(value)) => Some(value)
Some(VcfValue::List(values)) if values.length() > 0 =>
match values[0] {
VcfValue::Float(value) => Some(value)
_ => None
}
_ => None
}
}
///|
pub fn record_sample(record : VcfRecord, name : String) -> SampleCall? {
for sample in record.samples {
if sample.name == name {
return Some(sample)
}
}
None
}
///|
pub fn sample_value(sample : SampleCall, key : String) -> VcfValue? {
for pair in sample.values {
if pair.0 == key {
return Some(pair.1)
}
}
None
}
///|
pub fn record_sort_key(record : VcfRecord) -> String {
let alts = record.alt_alleles.join(",")
"\{record.chrom}:\{record.pos}:\{record.ref_allele}>\{alts}"
}
///|
pub fn sort_records(records : Array[VcfRecord]) -> Array[VcfRecord] {
let sorted : Array[VcfRecord] = []
for record in records {
let mut inserted = false
for index in 0.. Int {
if left.chrom < right.chrom {
-1
} else if left.chrom > right.chrom {
1
} else if left.pos < right.pos {
-1
} else if left.pos > right.pos {
1
} else if record_sort_key(left) < record_sort_key(right) {
-1
} else if record_sort_key(left) > record_sort_key(right) {
1
} else {
0
}
}
///|
pub fn group_record_counts(records : Array[VcfRecord]) -> Array[(String, Int)] {
let counts : Array[(String, Int)] = []
for record in records {
let mut found = false
for index, pair in counts {
if pair.0 == record.chrom {
counts[index] = (pair.0, pair.1 + 1)
found = true
break
}
}
if !found {
counts.push((record.chrom, 1))
}
}
counts
}