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