knuckles-parse 0.2.2

A tooklkit for parsing PDB records
Documentation
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg(feature = "python")]
use pyo3::prelude::*;

#[cfg(feature = "python")]
use knuckles_macro::pydefault;

#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "python", pydefault)]
pub struct AnisotropicRecord {
    pub serial: u32,
    pub name: String,
    pub alt_loc: Option<char>,
    pub res_name: String,
    pub chain_id: char,
    pub res_seq: i16,
    pub i_code: Option<char>,
    pub u00: i32,
    pub u11: i32,
    pub u22: i32,
    pub u01: i32,
    pub u02: i32,
    pub u12: i32,
    pub element: Option<String>,
    pub charge: Option<String>,
}

impl AnisotropicRecord {
    pub fn new(str: &str) -> AnisotropicRecord {
        AnisotropicRecord {
            serial: str[6..11].trim().parse::<u32>().unwrap_or_default(),
            name: str[12..16].trim().to_string(),
            alt_loc: str[16..17].trim().parse::<char>().ok(),
            res_name: str[17..20].trim().to_string(),
            chain_id: str[21..22].trim().parse::<char>().unwrap(),
            res_seq: str[22..26].trim().parse().unwrap(),
            i_code: str[26..27].trim().parse::<char>().ok(),
            u00: str[28..35].trim().parse().unwrap(),
            u11: str[35..42].trim().parse().unwrap(),
            u22: str[42..49].trim().parse().unwrap(),
            u01: str[49..56].trim().parse().unwrap(),
            u02: str[56..63].trim().parse().unwrap(),
            u12: str[63..70].trim().parse().unwrap(),
            element: str
                .get(76..78)
                .map(|str| str.trim().to_string())
                .filter(|item| !item.is_empty()),
            charge: str
                .get(78..80)
                .map(|str| str.trim().to_string())
                .filter(|item| !item.is_empty()),
        }
    }
}

impl From<&str> for AnisotropicRecord {
    fn from(str: &str) -> Self {
        AnisotropicRecord::new(str)
    }
}

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

    #[test]
    fn parse_anisou_line_test() {
        const LINE: &str =
            "ANISOU    1  N   MET A   1      688   1234    806    -19    -49    178       N  ";
        let record = AnisotropicRecord::new(LINE);
        assert_eq!(record.serial, 1);
        assert_eq!(record.name, "N");
        assert_eq!(record.res_name, "MET");
        assert_eq!(record.chain_id, 'A');
        assert_eq!(record.res_seq, 1);
        assert_eq!(record.u00, 688);
        assert_eq!(record.u11, 1234);
        assert_eq!(record.u22, 806);
        assert_eq!(record.u01, -19);
        assert_eq!(record.u02, -49);
        assert_eq!(record.u12, 178);
        assert_eq!(record.element, Some("N".to_string()));
        const LINE2: &str =
            "ANISOU    1  N   MET A   1      688   1234    806    -19    -49    178          ";
        let record = AnisotropicRecord::new(LINE2);
        assert_eq!(record.serial, 1);
        assert_eq!(record.name, "N");
        assert_eq!(record.res_name, "MET");
        assert_eq!(record.chain_id, 'A');
        assert_eq!(record.res_seq, 1);
        assert_eq!(record.u00, 688);
        assert_eq!(record.u11, 1234);
        assert_eq!(record.u22, 806);
        assert_eq!(record.u01, -19);
        assert_eq!(record.u02, -49);
        assert_eq!(record.u12, 178);
        assert_eq!(record.element, None);
    }
}