gen 0.1.0

A sequence graph and version control system.
Documentation
use crate::models::strand::Strand;
use convert_case::{Case, Casing};
use std::fs::File;
use std::io::{BufWriter, Write};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Segment {
    pub sequence: String,
    pub node_id: i64,
    pub sequence_start: i64,
    pub strand: Strand,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Link {
    pub source_segment_id: String,
    pub source_strand: Strand,
    pub target_segment_id: String,
    pub target_strand: Strand,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Path {
    pub name: String,
    pub segment_ids: Vec<String>,
    pub node_strands: Vec<Strand>,
}

impl Segment {
    pub fn segment_id(&self) -> String {
        format!("{}.{}", self.node_id, self.sequence_start)
    }
}

fn segment_line(segment: &Segment) -> String {
    // NOTE: We encode the node ID and start coordinate in the segment ID
    format!("S\t{}\t{}\t*\n", segment.segment_id(), segment.sequence)
}

fn link_line(link: &Link) -> String {
    format!(
        "L\t{}\t{}\t{}\t{}\t0M\n",
        link.source_segment_id, link.source_strand, link.target_segment_id, link.target_strand
    )
}

pub fn path_line(path: &Path) -> String {
    let segments = path
        .segment_ids
        .iter()
        .zip(path.node_strands.iter())
        .map(|(segment_id, node_strand)| format!("{}{}", segment_id, node_strand))
        .collect::<Vec<String>>()
        .join(",");
    format!("P\t{}\t{}\t*\n", path.name.to_case(Case::Train), segments)
}

pub fn write_segments(writer: &mut BufWriter<File>, segments: &Vec<Segment>) {
    for segment in segments {
        writer
            .write_all(&segment_line(segment).into_bytes())
            .unwrap_or_else(|_| {
                panic!(
                    "Error writing segment with sequence {} to GFA stream",
                    segment.sequence,
                )
            });
    }
}

pub fn write_links(writer: &mut BufWriter<File>, links: &Vec<Link>) {
    for link in links {
        writer
            .write_all(&link_line(link).into_bytes())
            .unwrap_or_else(|_| {
                panic!(
                    "Error writing link from segment {:?} to {:?} to GFA stream",
                    link.source_segment_id, link.target_segment_id,
                )
            });
    }
}