ctcore/read/
header.rs

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    // sss, xxx, rrr, ppp, iii, mmm
52    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           //aaabbblllfffcccsssxxxrrrpppiiimmmvvvvvv
178            "  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}