1use crate::{
2 build::Target,
3 molfile::{ChiralFlag, Counts, Header, MoleculeName, Parameters, Version},
4 primitive::{FixedCount, FixedInteger, FixedReal, Line, Sequence},
5};
6
7use super::{Error, Reader};
8
9pub fn header(reader: &mut Reader) -> Result<Header, Error> {
10 let molecule_name =
11 reader.read_line(Target::Builder(MoleculeName::start()))?;
12
13 let parameters = if reader.has_blank() {
14 reader.next_line()?;
15
16 None
17 } else {
18 let user_initials = reader.read(Target::Builder(Sequence::start()))?;
19 let program_name = reader.read(Target::Builder(Sequence::start()))?;
20 let timestamp = reader.read(Target::Builder(Sequence::start()))?;
21 let dimensional_codes =
22 reader.read(Target::Builder(Sequence::start()))?;
23 let major_scaling =
24 reader.read(Target::Builder(FixedInteger::start()))?;
25 let minor_scaling = reader.read(Target::Builder(FixedReal::start()))?;
26 let energy = reader.read(Target::Builder(FixedReal::start()))?;
27 let registry_number =
28 reader.read_line(Target::Builder(FixedInteger::start()))?;
29
30 Some(Parameters {
31 user_initials,
32 program_name,
33 timestamp,
34 dimensional_codes,
35 major_scaling,
36 minor_scaling,
37 energy,
38 registry_number,
39 })
40 };
41
42 let comment = reader.read_line(Target::Builder(Line::start()))?;
43 let atoms = reader.read(Target::Builder(FixedCount::start()))?;
44 let bonds = reader.read(Target::Builder(FixedCount::start()))?;
45 let atom_lists = reader.read(Target::Builder(FixedCount::start()))?;
46
47 reader.read(Target::Builder(Sequence::<3>::start()))?;
48
49 let chiral = reader.read(Target::Builder(ChiralFlag::start()))?;
50
51 reader.read(Target::Builder(Sequence::<18>::start()))?;
53
54 let version = reader.read_line(Target::Builder(Version::start()))?;
55
56 Ok(Header {
57 molecule_name,
58 parameters,
59 comment,
60 counts: Counts {
61 atoms,
62 bonds,
63 atom_lists,
64 chiral,
65 version,
66 },
67 })
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use pretty_assertions::assert_eq;
74
75 #[test]
76 fn eof() {
77 let mut bytes = b"".iter().cloned();
78 let mut reader = Reader::new(&mut bytes);
79
80 assert_eq!(header(&mut reader), Err(Error::Eof(0)))
81 }
82
83 #[test]
84 fn eof_after_user_initials() {
85 let mut bytes = vec!["", "AB"].join("\n").into_bytes().into_iter();
86 let mut reader = Reader::new(&mut bytes);
87
88 assert_eq!(header(&mut reader), Err(Error::Eof(1)))
89 }
90
91 #[test]
92 fn eof_after_program_name() {
93 let mut bytes =
94 vec!["", "AB-CTCORE-"].join("\n").into_bytes().into_iter();
95 let mut reader = Reader::new(&mut bytes);
96
97 assert_eq!(header(&mut reader), Err(Error::Eof(1)))
98 }
99
100 #[test]
101 fn eof_after_timestamp() {
102 let mut bytes = vec!["", "AB-CTCORE-0102030405"]
103 .join("\n")
104 .into_bytes()
105 .into_iter();
106 let mut reader = Reader::new(&mut bytes);
107
108 assert_eq!(header(&mut reader), Err(Error::Eof(1)))
109 }
110 #[test]
111 fn eof_after_dimensional_codes() {
112 let mut bytes = vec!["", "AB-CTCORE-01020304052D"]
113 .join("\n")
114 .into_bytes()
115 .into_iter();
116 let mut reader = Reader::new(&mut bytes);
117
118 assert_eq!(header(&mut reader), Err(Error::Eof(1)))
119 }
120
121 #[test]
122 fn eof_after_major_scaling_factor() {
123 let mut bytes = vec!["", "AB-CTCORE-01020304052D42"]
124 .join("\n")
125 .into_bytes()
126 .into_iter();
127 let mut reader = Reader::new(&mut bytes);
128
129 assert_eq!(header(&mut reader), Err(Error::Eof(1)))
130 }
131 #[test]
132 fn eof_after_minor_scaling_factor() {
133 let mut bytes = vec!["", "AB-CTCORE-01020304052D42 1.23456"]
134 .join("\n")
135 .into_bytes()
136 .into_iter();
137 let mut reader = Reader::new(&mut bytes);
138
139 assert_eq!(header(&mut reader), Err(Error::Eof(1)))
140 }
141
142 #[test]
143 fn eof_after_energy() {
144 let mut bytes =
145 vec!["", "AB-CTCORE-01020304052D42 1.23456 1.23456"]
146 .join("\n")
147 .into_bytes()
148 .into_iter();
149 let mut reader = Reader::new(&mut bytes);
150
151 assert_eq!(header(&mut reader), Err(Error::Eof(1)))
152 }
153
154 #[test]
155 fn eof_after_comment() {
156 let mut bytes = vec![
157 "Name",
158 "AB-CTCORE-01020304052D42 1.23456 1.23456 12345",
159 "COMMENT",
160 ]
161 .join("\n")
162 .into_bytes()
163 .into_iter();
164
165 let mut reader = Reader::new(&mut bytes);
166
167 assert_eq!(header(&mut reader), Err(Error::Eof(2)))
168 }
169
170 #[test]
171 #[rustfmt::skip]
172 fn parameters_blank_valid() {
173 let mut bytes = vec![
174 "Name",
175 "",
176 "Comment",
177 " 0 0 0 1 V3000",
179 ""
180 ]
181 .join("\n")
182 .into_bytes()
183 .into_iter();
184 let mut reader = Reader::new(&mut bytes);
185
186 assert_eq!(
187 header(&mut reader),
188 Ok(Header {
189 molecule_name: MoleculeName::from_str("Name").unwrap(),
190 parameters: None,
191 comment: Line::from_str("Comment").unwrap(),
192 counts: Counts {
193 atoms: FixedCount::Zero,
194 bonds: FixedCount::Zero,
195 atom_lists: FixedCount::Zero,
196 chiral: ChiralFlag::Chiral,
197 version: Version::V3,
198 }
199 })
200 )
201 }
202}