molframe_pdb/reader/
entry.rs1use super::ensemble::{CommonRecords, read_ragged};
4use super::lines::{Line, Lines};
5use super::numbers::decode_window;
6use super::state::ReadState;
7use molframe_core::diagnostic::{Code, Diagnostic};
8use molframe_core::execution::ExecutionContext;
9use molframe_core::io::{Format, InputBuffer, ReadOptions, ReadResult, Reader};
10
11#[derive(Clone, Copy, Debug, Default)]
13pub struct PdbReader;
14
15impl Reader for PdbReader {
16 const FORMAT: Format = Format::Pdb;
17
18 fn read(input: &InputBuffer, options: &ReadOptions) -> ReadResult {
19 read_as(input, options, Format::Pdb)
20 }
21}
22
23pub fn read(input: &InputBuffer, options: &ReadOptions) -> ReadResult {
30 read_as(input, options, Format::Pdb)
31}
32
33pub fn read_pqr(input: &InputBuffer, options: &ReadOptions) -> ReadResult {
40 read_as(input, options, Format::Pqr)
41}
42
43pub fn read_pdbqt(input: &InputBuffer, options: &ReadOptions) -> ReadResult {
50 read_as(input, options, Format::Pdbqt)
51}
52
53const WINDOW_LINES: usize = 1 << 15;
55
56fn read_as(input: &InputBuffer, options: &ReadOptions, variant: Format) -> ReadResult {
57 let Ok(text) = str::from_utf8(input.as_bytes()) else {
58 return Err(vec![
59 Diagnostic::new(Code::E1201).with_message("input is not valid text"),
60 ]);
61 };
62
63 let mut common = CommonRecords::new();
64 let mut state = ReadState::new(options, variant);
65 let context = ExecutionContext::default();
66 let mut lines = Lines::new(text);
67 let mut window = Vec::with_capacity(WINDOW_LINES);
68 loop {
69 window.clear();
70 let mut failure = None;
71 for line in lines.by_ref().take(WINDOW_LINES) {
72 match line {
73 Ok(line) => window.push(line),
74 Err(finding) => {
75 failure = Some(finding);
76 break;
77 }
78 }
79 }
80 let decoded = decode_window(&window, &context);
81 for (index, line) in window.iter().enumerate() {
82 common.observe(line);
83 let line = Line {
84 numbers: decoded.get(index).and_then(Option::as_ref),
85 ..*line
86 };
87 state.line(&line);
88 }
89 if let Some(finding) = failure {
90 return Err(vec![finding]);
91 }
92 if window.len() < WINDOW_LINES {
93 break;
94 }
95 }
96 if state.requires_ragged() {
97 drop(state);
98 return read_ragged(text, options, variant, &common);
99 }
100 state.finish()
101}
102
103#[cfg(test)]
104#[path = "entry_tests.rs"]
105mod tests;