knuckles_parse/records/
term.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4#[cfg(feature = "python")]
5use pyo3::prelude::*;
6
7#[cfg(feature = "python")]
8use knuckles_macro::pydefault;
9
10/// Represents a TER (termination) record indicating the end of a chain.
11///
12/// TER records are used to indicate the end of a list of ATOM/HETATM records for a chain.
13///
14/// # Fields
15///
16/// - `serial`: Serial number of the terminating atom
17/// - `res_name`: Residue name of the terminating residue  
18/// - `chain_id`: Chain identifier
19/// - `res_seq`: Residue sequence number
20/// - `i_code`: Insertion code
21#[derive(Debug, Clone)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
24#[cfg_attr(feature = "python", pydefault)]
25pub struct TermRecord {
26    /// Serial number of the terminating atom
27    pub serial: u32,
28    /// Residue name of the terminating residue
29    pub res_name: String,
30    /// Chain identifier
31    pub chain_id: char,
32    /// Residue sequence number
33    pub res_seq: i16,
34    /// Insertion code
35    pub i_code: Option<char>,
36}
37
38impl TermRecord {
39    /// Create a new TermRecord by parsing a TER line.
40    pub fn new(str: &str) -> TermRecord {
41        TermRecord {
42            serial: str[6..11].trim().parse().unwrap_or_default(),
43            res_name: str[17..20].trim().to_string(),
44            chain_id: str[21..22].parse().unwrap_or_default(),
45            res_seq: str[22..26].trim().parse().unwrap_or_default(),
46            i_code: str
47                .get(26..27)
48                .map(|s| s.parse().unwrap_or_default())
49                .filter(|item| *item != ' '),
50        }
51    }
52}
53
54impl From<&str> for TermRecord {
55    fn from(str: &str) -> Self {
56        TermRecord::new(str)
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_new() {
66        let str =
67            "TER     297      ALA A  18                                                      ";
68        let record = TermRecord::new(str);
69        assert_eq!(record.serial, 297);
70        assert_eq!(record.res_name, "ALA");
71        assert_eq!(record.chain_id, 'A');
72        assert_eq!(record.res_seq, 18);
73        assert_eq!(record.i_code, None);
74    }
75
76    #[test]
77    fn test_from() {
78        let str =
79            "TER     297      ALA A  18                                                      ";
80        let record = TermRecord::from(str);
81        assert_eq!(record.serial, 297);
82        assert_eq!(record.res_name, "ALA");
83        assert_eq!(record.chain_id, 'A');
84        assert_eq!(record.res_seq, 18);
85        assert_eq!(record.i_code, None);
86    }
87}