molframe_pdb/header/
records.rs1use molframe_core::Structure;
2
3pub const PDB_HEADERS_EXTENSION: &str = "molframe.pdb.headers.v1";
5
6#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct PdbHeaderRecord {
9 name: Box<str>,
10 line: Box<str>,
11}
12
13impl PdbHeaderRecord {
14 pub(crate) fn new(name: &str, line: &str) -> Self {
15 Self {
16 name: name.into(),
17 line: line.into(),
18 }
19 }
20
21 #[must_use]
23 pub fn name(&self) -> &str {
24 &self.name
25 }
26
27 #[must_use]
29 pub fn line(&self) -> &str {
30 &self.line
31 }
32}
33
34#[derive(Clone, Debug, Default, PartialEq, Eq)]
36pub struct PdbHeaders {
37 records: Vec<PdbHeaderRecord>,
38}
39
40impl PdbHeaders {
41 pub(crate) fn push(&mut self, name: &str, line: &str) {
42 self.records.push(PdbHeaderRecord::new(name, line));
43 }
44
45 #[must_use]
47 pub fn is_empty(&self) -> bool {
48 self.records.is_empty()
49 }
50
51 #[must_use]
53 pub fn records(&self) -> &[PdbHeaderRecord] {
54 &self.records
55 }
56
57 pub fn named<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a PdbHeaderRecord> {
59 self.records
60 .iter()
61 .filter(move |record| record.name.as_ref() == name)
62 }
63
64 #[must_use]
66 pub fn classification(&self) -> Option<&str> {
67 self.header_field(10, 50)
68 }
69
70 #[must_use]
72 pub fn deposition_date(&self) -> Option<&str> {
73 self.header_field(50, 59)
74 }
75
76 fn header_field(&self, start: usize, end: usize) -> Option<&str> {
77 let header = self.named("HEADER").next()?.line();
78 let value = header.get(start..end)?.trim();
79 (!value.is_empty()).then_some(value)
80 }
81}
82
83pub trait PdbHeadersExt {
85 fn pdb_headers(&self) -> Option<&PdbHeaders>;
87}
88
89impl PdbHeadersExt for Structure {
90 fn pdb_headers(&self) -> Option<&PdbHeaders> {
91 self.extensions().get(PDB_HEADERS_EXTENSION)
92 }
93}
94
95pub(crate) fn is_metadata_record(name: &str) -> bool {
97 matches!(
98 name,
99 "HEADER"
100 | "OBSLTE"
101 | "TITLE"
102 | "SPLIT"
103 | "CAVEAT"
104 | "COMPND"
105 | "SOURCE"
106 | "KEYWDS"
107 | "EXPDTA"
108 | "NUMMDL"
109 | "MDLTYP"
110 | "AUTHOR"
111 | "REVDAT"
112 | "SPRSDE"
113 | "JRNL"
114 | "REMARK"
115 | "DBREF"
116 | "DBREF1"
117 | "DBREF2"
118 | "SEQADV"
119 | "SEQRES"
120 | "MODRES"
121 | "HET"
122 | "HETNAM"
123 | "HETSYN"
124 | "FORMUL"
125 | "HELIX"
126 | "SHEET"
127 | "SSBOND"
128 | "LINK"
129 | "CISPEP"
130 | "SITE"
131 | "CRYST1"
132 | "ORIGX1"
133 | "ORIGX2"
134 | "ORIGX3"
135 | "SCALE1"
136 | "SCALE2"
137 | "SCALE3"
138 | "MTRIX1"
139 | "MTRIX2"
140 | "MTRIX3"
141 )
142}