seal 0.1.6

Implementation of Needleman-Wunsch & Smith-Waterman sequence alignment.
Documentation
use crate::pair::alignment::Alignment;
use crate::pair::alignment_matrix::AlignmentMatrix;
use crate::pair::cursor::Cursor;
use crate::pair::step_mask::StepMask;

pub struct Alignments<'a, T: 'a> {
    matrix: &'a T,
    stack: Vec<(StepMask, Cursor, usize)>,
    steps: Vec<StepMask>,
    score: isize,
}

impl<'a, T> Alignments<'a, T> {
    pub fn new(
        matrix: &'a T,
        stack: Vec<(StepMask, Cursor, usize)>,
        steps: Vec<StepMask>,
        score: isize,
    ) -> Self {
        Alignments {
            matrix,
            stack,
            steps,
            score,
        }
    }
}

impl<'a, T> Alignments<'a, T>
where
    T: AlignmentMatrix,
{
    fn branches(&self, cursor: Cursor) -> Vec<(StepMask, Cursor)> {
        let steps = self.matrix.at(&cursor);
        let mut branches = vec![];
        if steps == StepMask::STOP {
            return branches;
        }
        for mask in [StepMask::ALIGN, StepMask::INSERT, StepMask::DELETE].iter() {
            if steps.contains(*mask) {
                let mut branch = cursor;
                branch.apply_backwards_step(*mask);
                branches.push((*mask, branch));
            }
        }
        branches
    }
}

impl<'a, T> Iterator for Alignments<'a, T>
where
    T: AlignmentMatrix,
{
    type Item = Alignment;

    fn next(&mut self) -> Option<Alignment> {
        let zero = Cursor { x: 0, y: 0 };
        while let Some((step_mask, cursor, depth)) = self.stack.pop() {
            if step_mask != StepMask::STOP {
                self.steps.truncate(depth - 1);
                self.steps.push(step_mask);
            }
            let branches = self.branches(cursor);
            for (step_mask, cursor) in branches {
                self.stack.push((step_mask, cursor, depth + 1));
            }
            if ((step_mask == StepMask::STOP) && (depth > 0)) || (cursor == zero) {
                let mut steps: Vec<StepMask> = self.steps.clone();
                steps.reverse();
                return Some(Alignment::new(cursor, steps, self.score));
            }
        }
        None
    }
}