use crate::headers::{Header, GraphPayload};
use crate::support::{StringArray, StringIter};
use simple_sds::ops::{BitVec, Select, PredSucc};
use simple_sds::serialize::Serialize;
use simple_sds::sparse_vector::{SparseVector, OneIter};
use std::io::{Error, ErrorKind};
use std::iter::FusedIterator;
use std::ops::Range;
use std::io;
#[cfg(test)]
mod tests;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Graph {
header: Header<GraphPayload>,
sequences: StringArray,
segments: StringArray,
mapping: SparseVector,
}
impl Graph {
#[inline]
pub fn nodes(&self) -> usize {
self.header.payload().nodes
}
#[inline]
pub fn sequences(&self) -> usize {
self.sequences.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.sequences.is_empty()
}
#[inline]
pub fn sequence(&self, id: usize) -> &[u8] {
self.sequences.bytes(id)
}
#[inline]
pub fn sequence_len(&self, id: usize) -> usize {
self.sequences.str_len(id)
}
pub fn iter(&self) -> StringIter {
self.sequences.iter()
}
}
impl Graph {
#[inline]
pub fn has_translation(&self) -> bool {
self.header.is_set(GraphPayload::FLAG_TRANSLATION)
}
#[inline]
pub fn segments(&self) -> usize {
self.segments.len()
}
pub fn segment(&self, id: usize) -> Segment {
let name = self.segment_name(id);
let nodes = self.segment_nodes(id);
let sequence = self.sequences.range(nodes.start - 1..nodes.end - 1);
Segment::from_fields(id, name, nodes, sequence)
}
pub fn node_to_segment(&self, node_id: usize) -> Segment {
let mut iter = self.mapping.predecessor(node_id);
let (segment_id, start) = iter.next().unwrap();
let end = if let Some((_, value)) = iter.next() { value } else { self.mapping.len() };
let name = self.segment_name(segment_id);
let sequence = self.sequences.range(start - 1..end - 1);
Segment {
id: segment_id,
name,
nodes: start..end,
sequence,
}
}
#[inline]
pub fn segment_name(&self, id: usize) -> &[u8] {
self.segments.bytes(id)
}
pub fn segment_nodes(&self, id: usize) -> Range<usize> {
let mut iter = self.mapping.select_iter(id);
let (_, start) = iter.next().unwrap();
let end = if let Some((_, value)) = iter.next() { value } else { self.mapping.len() };
start..end
}
pub fn segment_range(&self, id: usize) -> Range<usize> {
let range = self.segment_nodes(id);
range.start - 1..range.end - 1
}
pub fn segment_sequence(&self, id: usize) -> &[u8] {
let range = self.segment_range(id);
self.sequences.range(range)
}
pub fn segment_len(&self, id: usize) -> usize {
let range = self.segment_range(id);
self.sequences.range_len(range)
}
pub fn segment_iter(&self) -> SegmentIter {
let mut iter = self.mapping.one_iter();
let first_node = if let Some((_, value)) = iter.next() { value } else { 0 };
let next = (0, first_node);
let limit = (self.segments(), self.mapping.len());
SegmentIter {
parent: self,
iter,
next,
limit,
}
}
}
impl Serialize for Graph {
fn serialize_header<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
self.header.serialize(writer)
}
fn serialize_body<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
self.sequences.serialize(writer)?;
self.segments.serialize(writer)?;
self.mapping.serialize(writer)?;
Ok(())
}
fn load<T: io::Read>(reader: &mut T) -> io::Result<Self> {
let header = Header::<GraphPayload>::load(reader)?;
if let Err(msg) = header.validate() {
return Err(Error::new(ErrorKind::InvalidData, msg));
}
let sequences = StringArray::load(reader)?;
let segments = StringArray::load(reader)?;
if header.is_set(GraphPayload::FLAG_TRANSLATION) == segments.is_empty() {
return Err(Error::new(ErrorKind::InvalidData, "Graph: Translation flag does not match the presence of segment names"));
}
let mapping = SparseVector::load(reader)?;
if header.is_set(GraphPayload::FLAG_TRANSLATION) {
if mapping.len() <= header.payload().nodes {
return Err(Error::new(ErrorKind::InvalidData, "Graph: Node-to-segment mapping does not match the number of nodes"));
}
if mapping.len() != sequences.len() + 1 {
return Err(Error::new(ErrorKind::InvalidData, "Graph: Node-to-segment mapping does not match the number of sequences"));
}
if mapping.count_ones() != segments.len() {
return Err(Error::new(ErrorKind::InvalidData, "Graph: Node-to-segment mapping does not match the number of segments"));
}
} else if !segments.is_empty() {
return Err(Error::new(ErrorKind::InvalidData, "Graph: Translation flag does not match the presence of node-to-segment mapping"));
}
Ok(Graph {
header, sequences, segments, mapping,
})
}
fn size_in_elements(&self) -> usize {
self.header.size_in_elements() + self.sequences.size_in_elements() + self.segments.size_in_elements() + self.mapping.size_in_elements()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Segment<'a> {
pub id: usize,
pub name: &'a [u8],
pub nodes: Range<usize>,
pub sequence: &'a [u8],
}
impl<'a> Segment<'a> {
pub fn from_fields(id: usize, name: &'a [u8], nodes: Range<usize>, sequence: &'a [u8]) -> Self {
Segment {
id, name, nodes, sequence,
}
}
}
#[derive(Clone, Debug)]
pub struct SegmentIter<'a> {
parent: &'a Graph,
iter: OneIter<'a>,
next: (usize, usize),
limit: (usize, usize),
}
impl<'a> Iterator for SegmentIter<'a> {
type Item = Segment<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.next.0 >= self.limit.0 {
None
} else {
let id = self.next.0;
self.next.0 += 1;
let name = self.parent.segments.bytes(id);
let prev = self.next.1;
self.next.1 = if let Some((_, value)) = self.iter.next() { value } else { self.limit.1 };
let sequence = self.parent.sequences.range(prev - 1..self.next.1 - 1);
Some(Segment::from_fields(id, name, prev..self.next.1, sequence))
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.limit.0 - self.next.0;
(remaining, Some(remaining))
}
}
impl<'a> DoubleEndedIterator for SegmentIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.next.0 >= self.limit.0 {
None
} else {
self.limit.0 -= 1;
let id = self.limit.0;
let name = self.parent.segments.bytes(id);
let old_node_limit = self.limit.1;
self.limit.1 = if let Some((_, value)) = self.iter.next_back() { value } else { self.next.1 };
let sequence = self.parent.sequences.range(self.limit.1 - 1..old_node_limit - 1);
Some(Segment::from_fields(id, name, self.limit.1..old_node_limit, sequence))
}
}
}
impl<'a> ExactSizeIterator for SegmentIter<'a> {}
impl<'a> FusedIterator for SegmentIter<'a> {}