Skip to main content

molframe_pdb/reader/
entry.rs

1//! The entry point: bytes in, structure and findings out.
2
3use super::ensemble::{CommonRecords, read_ragged};
4use super::lines::Lines;
5use super::state::ReadState;
6use molframe_core::diagnostic::{Code, Diagnostic};
7use molframe_core::io::{Format, InputBuffer, ReadOptions, ReadResult, Reader};
8
9/// The reader for the legacy fixed-column format.
10#[derive(Clone, Copy, Debug, Default)]
11pub struct PdbReader;
12
13impl Reader for PdbReader {
14    const FORMAT: Format = Format::Pdb;
15
16    fn read(input: &InputBuffer, options: &ReadOptions) -> ReadResult {
17        read_as(input, options, Format::Pdb)
18    }
19}
20
21/// Reads a structure from fixed-column text.
22///
23/// # Errors
24///
25/// Returns the findings that stopped the read: text that is not valid UTF-8, or
26/// a file with no coordinate records in it at all.
27pub fn read(input: &InputBuffer, options: &ReadOptions) -> ReadResult {
28    read_as(input, options, Format::Pdb)
29}
30
31/// Reads PQR coordinates with partial charge and radius annotations.
32///
33/// # Errors
34///
35/// Returns findings when text, coordinate fields or variant values cannot be
36/// interpreted under the requested parse mode.
37pub fn read_pqr(input: &InputBuffer, options: &ReadOptions) -> ReadResult {
38    read_as(input, options, Format::Pqr)
39}
40
41/// Reads PDBQT coordinates with partial charge and `AutoDock` type annotations.
42///
43/// # Errors
44///
45/// Returns findings when text, coordinate fields or variant values cannot be
46/// interpreted under the requested parse mode.
47pub fn read_pdbqt(input: &InputBuffer, options: &ReadOptions) -> ReadResult {
48    read_as(input, options, Format::Pdbqt)
49}
50
51fn read_as(input: &InputBuffer, options: &ReadOptions, variant: Format) -> ReadResult {
52    let Ok(text) = str::from_utf8(input.as_bytes()) else {
53        return Err(vec![
54            Diagnostic::new(Code::E1201).with_message("input is not valid text"),
55        ]);
56    };
57
58    let mut common = CommonRecords::new();
59    let mut state = ReadState::new(options, variant);
60    for line in Lines::new(text) {
61        let line = line.map_err(|finding| vec![finding])?;
62        common.observe(&line);
63        state.line(&line);
64    }
65    if state.requires_ragged() {
66        drop(state);
67        return read_ragged(text, options, variant, &common);
68    }
69    state.finish()
70}
71
72#[cfg(test)]
73#[path = "entry_tests.rs"]
74mod tests;