lib_ts_chainalign 2.1.1

A chaining-based sequence-to-sequence aligner that accounts for template switches
Documentation
use std::{
    io::{Read, Write},
    mem,
    ops::{Index, IndexMut},
    slice,
};

use log::trace;

pub struct LowerBoundCostArray<const DIMENSION: usize, Cost> {
    dim: [usize; DIMENSION],
    data: Vec<Cost>,
}

impl<const DIMENSION: usize, Cost> LowerBoundCostArray<DIMENSION, Cost> {
    pub fn new_from_cost(dim: [usize; DIMENSION], cost: Cost) -> Self
    where
        Cost: Clone,
    {
        Self {
            dim,
            data: vec![cost; dim.into_iter().product()],
        }
    }

    pub fn write(&self, mut write: impl Write) -> std::io::Result<()>
    where
        Cost: Copy,
    {
        for dimension in self.dim {
            write.write_all(&dimension.to_ne_bytes())?;
        }

        let cost_size = mem::size_of::<Cost>();
        let data: &[u8] = unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8, self.data.len() * cost_size)
        };
        write.write_all(data)
    }

    pub fn read(mut read: impl Read) -> std::io::Result<Self>
    where
        Cost: Copy,
    {
        let mut buffer = [0; mem::size_of::<usize>()];
        let mut dim = [0usize; DIMENSION];
        for dimension in &mut dim {
            read.read_exact(&mut buffer)?;
            *dimension = usize::from_ne_bytes(buffer);
        }
        let dim = dim;
        trace!("Read dimensions: {dim:?}");

        let cost_size = mem::size_of::<Cost>();
        let data_len = dim.into_iter().product();
        let data_bytes_len = cost_size * data_len;

        let mut data = Vec::<Cost>::with_capacity(data_bytes_len);
        let mut data_bytes = unsafe {
            Vec::from_raw_parts(data.as_mut_ptr() as *mut u8, 0, data.capacity() * cost_size)
        };
        read.by_ref()
            .take(data_bytes_len.try_into().unwrap())
            .read_to_end(&mut data_bytes)?;
        unsafe {
            data.set_len(data_len);
        };
        data_bytes.leak();

        Ok(Self { dim, data })
    }
}

impl<const DIMENSION: usize, Cost> Index<[usize; DIMENSION]>
    for LowerBoundCostArray<DIMENSION, Cost>
{
    type Output = Cost;

    fn index(&self, index: [usize; DIMENSION]) -> &Self::Output {
        &self.data[coordinates_to_index(index, self.dim)]
    }
}

impl<const DIMENSION: usize, Cost> IndexMut<[usize; DIMENSION]>
    for LowerBoundCostArray<DIMENSION, Cost>
{
    fn index_mut(&mut self, index: [usize; DIMENSION]) -> &mut Self::Output {
        &mut self.data[coordinates_to_index(index, self.dim)]
    }
}

impl<Cost> FromIterator<Cost> for LowerBoundCostArray<1, Cost> {
    fn from_iter<T: IntoIterator<Item = Cost>>(iter: T) -> Self {
        let data: Vec<_> = iter.into_iter().collect();
        let dim = [data.len()];
        Self { dim, data }
    }
}

#[inline]
fn coordinates_to_index<const DIMENSION: usize>(
    coordinates: [usize; DIMENSION],
    dim: [usize; DIMENSION],
) -> usize {
    let mut result = 0;
    for (index, ordinate) in coordinates.into_iter().enumerate() {
        result += dim.into_iter().skip(index + 1).product::<usize>() * ordinate;
    }
    result
}