md_analysis 0.1.0

molecular dynamics
use rust_htslib::bam::Record;

/// 流水线中间消息类型
///
/// RecordData:从 BAM record 序列化而来,供 stats workers 使用。
/// 解决 rust_htslib::bam::Record 不 Send 的问题——所有数据转为纯值类型(String、Vec<u8>、Vec<u64>)。
use crate::bam_record_ext::BamRecordExt;

/// 从 BAM record 提取的记录数据,可跨线程发送。
///
/// `bases` / `dw_bins` / `ar_bins` 的每个子 Vec 对应一个 region(first_n、last_n)。
/// slice_n == 0 时只有一个 "full" 元素包含全部位置。
#[derive(Clone, Debug)]
pub struct RecordData {
    pub name: String,
    pub seq_len: usize,
    pub bases: String,
    pub dw: Vec<u32>,
    pub ar: Vec<u32>,
}

impl From<&Record> for RecordData {
    fn from(value: &Record) -> Self {
        let record_ext = BamRecordExt::new(value);
        let name = record_ext.get_qname();
        let seq_len = value.seq_len();
        let bases = record_ext.get_seq();
        let dw = record_ext.get_dw().unwrap();
        let ar = record_ext.get_ar().unwrap();
        Self {
            name,
            seq_len,
            bases,
            dw,
            ar,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn record_data_type_exists() {
        let rd = RecordData {
            name: String::new(),
            seq_len: 0,
            bases: String::new(),
            dw: vec![],
            ar: vec![],
        };
        assert_eq!(rd.name, "");
        assert_eq!(rd.seq_len, 0);
    }

    #[test]
    fn record_data_debug_fmt() {
        let rd = RecordData {
            name: "read1".into(),
            seq_len: 100,
            bases: "ATGC".into(),
            dw: vec![1, 2],
            ar: vec![3, 4],
        };
        let s = format!("{rd:?}");
        assert!(s.contains("read1"));
        assert!(s.contains("bases"));
    }

    #[test]
    fn record_data_clone() {
        let rd = RecordData {
            name: "read2".into(),
            seq_len: 50,
            bases: "ACGT".into(),
            dw: vec![1],
            ar: vec![2],
        };
        let rd2 = rd.clone();
        assert_eq!(rd.name, rd2.name);
        assert_eq!(rd.seq_len, rd2.seq_len);
        assert_eq!(rd.bases, rd2.bases);
        assert_eq!(rd.dw, rd2.dw);
        assert_eq!(rd.ar, rd2.ar);
    }
}