seal 0.1.6

Implementation of Needleman-Wunsch & Smith-Waterman sequence alignment.
Documentation
use std::{fmt, fs, io, mem};

use memmap2::MmapMut;
use tempfile::tempdir;
use uuid::Uuid;

use crate::pair::cursor::Cursor;
use crate::pair::step_mask::StepMask;

use super::AlignmentMatrix as AlignmentMatrixTrait;

pub struct AlignmentMatrix {
    width: usize,
    height: usize,
    mmap: MmapMut,
}

impl AlignmentMatrix {
    fn offset(&self, cursor: &Cursor) -> usize {
        cursor.x + (cursor.y * self.width)
    }
}

impl AlignmentMatrixTrait for AlignmentMatrix {
    type Error = io::Error;

    fn new(width: usize, height: usize) -> Result<Self, Self::Error> {
        let tempdir = tempdir()?;
        let directory = tempdir.path();
        let uuid = Uuid::new_v4();
        let filename = uuid.as_simple().to_string();
        let path = directory.join(filename);
        let file = fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&path)?;
        let size = (width + 1) * (height + 1);
        file.set_len(size as u64)?;
        let mmap = unsafe { MmapMut::map_mut(&file)? };
        Ok(Self {
            width,
            height,
            mmap,
        })
    }

    fn width(&self) -> usize {
        self.width
    }

    fn height(&self) -> usize {
        self.height
    }

    fn at(&self, cursor: &Cursor) -> StepMask {
        let offset = self.offset(cursor);
        unsafe {
            let byte = self.mmap.get_unchecked(offset);
            mem::transmute::<u8, StepMask>(*byte)
        }
    }

    fn set_at(&mut self, cursor: &Cursor, step_mask: StepMask) {
        let offset = self.offset(cursor);
        let byte = unsafe { mem::transmute::<StepMask, u8>(step_mask) };
        let byte_ref = unsafe { self.mmap.get_unchecked_mut(offset) };
        *byte_ref = byte;
    }
}

impl fmt::Debug for AlignmentMatrix {
    fn fmt(&self, form: &mut fmt::Formatter) -> fmt::Result {
        for y in 0..self.height() {
            for x in 0..self.width() {
                let cursor = Cursor { x, y };
                let _ = write!(form, "{:?}\t", self.at(&cursor));
            }
            let _ = writeln!(form);
        }
        writeln!(form)
    }
}