use anyhow::Ok;
use libsufr::types::SequenceFileData;
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
pub(crate) struct SequenceMetadata {
start_position: usize,
header: String,
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
pub(crate) struct SequenceIndex {
sequences: Vec<SequenceMetadata>,
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
pub struct LocalizedSequencePosition {
sequence_idx: usize,
local_position: usize,
}
impl LocalizedSequencePosition {
pub fn new(sequence_idx: usize, local_position: usize) -> Self {
LocalizedSequencePosition {
sequence_idx,
local_position,
}
}
pub fn sequence_idx(&self) -> usize {
self.sequence_idx
}
pub fn local_position(&self) -> usize {
self.local_position
}
}
impl SequenceIndex {
pub(crate) fn new() -> Self {
SequenceIndex {
sequences: Vec::new(),
}
}
pub(crate) fn from_seq_file_data(seq_file_data: &SequenceFileData) -> Self {
let mut sequence_index: SequenceIndex = SequenceIndex::new();
for seq_idx in 0..seq_file_data.headers.len() {
sequence_index.add_sequence(
&seq_file_data.headers[seq_idx],
seq_file_data.start_positions[seq_idx],
);
}
return sequence_index;
}
pub(crate) fn add_sequence(&mut self, header: &str, start_position: usize) {
self.sequences.push(SequenceMetadata {
start_position,
header: header.to_string(),
})
}
pub(crate) fn get_seq_location(
&self,
global_position: usize,
) -> Option<LocalizedSequencePosition> {
return self.find_sequence_binary_search(global_position, 0, self.sequences.len() - 1);
}
fn find_sequence_binary_search(
&self,
global_position: usize,
range_low: usize,
range_high: usize,
) -> Option<LocalizedSequencePosition> {
if range_low == range_high {
return Some(LocalizedSequencePosition::new(
range_low,
global_position - self.sequences[range_low].start_position,
));
}
let midpoint = (range_low + range_high) / 2;
if self.sequences[midpoint].start_position > global_position {
self.find_sequence_binary_search(global_position, range_low, midpoint)
} else if self.sequences[midpoint].start_position < global_position {
self.find_sequence_binary_search(global_position, midpoint, range_high)
} else {
Some(LocalizedSequencePosition {
sequence_idx: midpoint,
local_position: global_position - self.sequences[midpoint].start_position,
})
}
}
pub(crate) fn serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<(), anyhow::Error> {
writer.write_all(&(self.sequences.len() as u64).to_le_bytes())?;
for sequence in self.sequences.iter() {
writer.write_all(&(sequence.start_position as u64).to_le_bytes())?;
writer.write_all(&(sequence.header.len() as u64).to_le_bytes())?;
writer.write_all(sequence.header.as_bytes())?;
}
return Ok(());
}
pub(crate) fn from_file<R: std::io::Read>(reader: &mut R) -> Result<Self, anyhow::Error> {
let mut sequence_index: SequenceIndex = SequenceIndex::new();
let mut u64_buffer: [u8; 8] = [0; 8];
reader.read_exact(&mut u64_buffer)?;
let num_sequences = u64::from_le_bytes(u64_buffer);
for _ in 0..num_sequences {
reader.read_exact(&mut u64_buffer)?;
let start_position = u64::from_le_bytes(u64_buffer) as usize;
reader.read_exact(&mut u64_buffer)?;
let header_len = u64::from_le_bytes(u64_buffer);
let mut header_string = String::new();
header_string.reserve(header_len as usize);
for _ in 0..header_len{
let mut buf:[u8;1] = [0;1];
let _ = &reader.read(&mut buf);
header_string.push(buf[0] as char);
}
sequence_index.add_sequence(&header_string, start_position);
}
return Ok(sequence_index);
}
}