hts 0.1.17

Rust binding for htslib
Documentation
use super::Alignment;
use crate::TypedValue;
use std::ffi::CStr;

impl<'a> TypedValue<'a> {
    fn parse_fix_sized_data<T: Sized + 'static, F: Fn(&'a [T]) -> TypedValue<'a>>(
        cursor: &'a [u8],
        count: usize,
        f: F,
    ) -> Option<(TypedValue, &'a [u8])> {
        if count * std::mem::size_of::<T>() > cursor.len() {
            return None;
        }
        Some((
            f(unsafe { std::slice::from_raw_parts(&cursor[0] as *const u8 as *const T, count) }),
            &cursor[std::mem::size_of::<T>() * count..],
        ))
    }
    fn parse_typed_value(cursor: &'a [u8], count: usize) -> Option<(TypedValue<'a>, &'a [u8])> {
        use TypedValue::*;
        match cursor[0] {
            b'c' => Self::parse_fix_sized_data(&cursor[1..], count, I8),
            b'C' | b'A' => Self::parse_fix_sized_data(&cursor[1..], count, U8),
            b's' => Self::parse_fix_sized_data(&cursor[1..], count, I16),
            b'S' => Self::parse_fix_sized_data(&cursor[1..], count, U16),
            b'i' => Self::parse_fix_sized_data(&cursor[1..], count, I32),
            b'I' => Self::parse_fix_sized_data(&cursor[1..], count, U32),
            b'f' => Self::parse_fix_sized_data(&cursor[1..], count, F),
            _ => None,
        }
    }
    fn parse_aux_data(cursor: &'a [u8]) -> Option<(TypedValue<'a>, &'a [u8])> {
        match cursor.get(0)? {
            b'H' | b'Z' => {
                let value = unsafe { CStr::from_ptr(&cursor[1..] as *const _ as *const i8) };
                let length = value.to_bytes().len();
                Some((TypedValue::Str(value), &cursor[2 + length..]))
            }
            b'B' => {
                let size =
                    u32::from_le_bytes([cursor[1], cursor[2], cursor[3], cursor[4]]) as usize;
                Self::parse_typed_value(&cursor[5..], size)
            }
            _ => Self::parse_typed_value(cursor, 1),
        }
    }
}

pub struct AuxDataIter<'a> {
    data: &'a [u8],
    offset: usize,
}

impl<'a> Iterator for AuxDataIter<'a> {
    type Item = ([u8; 2], TypedValue<'a>);
    fn next(&mut self) -> Option<Self::Item> {
        if self.offset + 2 > self.data.len() {
            return None;
        }
        let label = [self.data[self.offset], self.data[self.offset + 1]];
        let (data, rem) = TypedValue::parse_aux_data(&self.data[self.offset + 2..])?;
        let new_offset = self.data.len() - rem.len();
        self.offset = new_offset;
        Some((label, data))
    }
}

impl<'a> Alignment<'a> {
    pub fn aux_iter(&self) -> AuxDataIter {
        AuxDataIter {
            data: self.raw_aux(),
            offset: 0,
        }
    }
}