use crate::fixed;
use crate::hybrid36;
use crate::reader::lines::Line;
use molframe_core::column::Presence;
use molframe_core::optional::OptionalI32;
#[must_use]
pub(crate) fn starts_with_coordinate_keyword(line: &str) -> bool {
let name = fixed::record(line);
for keyword in ["ATOM", "HETATM"] {
if let Some(rest) = name.strip_prefix(keyword) {
let rest = rest.trim_start();
if !rest.is_empty() && rest.bytes().all(|byte| byte.is_ascii_digit()) {
return true;
}
}
}
false
}
#[must_use]
pub(crate) fn sequence_identifier(sequence: i64) -> OptionalI32 {
match i32::try_from(sequence) {
Ok(sequence) => OptionalI32::some(sequence),
Err(_) => OptionalI32::NONE,
}
}
#[must_use]
pub(crate) fn serial_of(line: &Line<'_>) -> u32 {
match line.numbers {
Some(numbers) => numbers.serial,
None => serial_in(line.text),
}
}
pub(crate) fn serial_in(text: &str) -> u32 {
let Some(serial) =
hybrid36::decode(fixed::raw(text, 7, 11), 5).and_then(|serial| u32::try_from(serial).ok())
else {
return 0;
};
serial
}
#[cfg(test)]
#[path = "rows_tests.rs"]
mod tests;
pub(in crate::reader) fn charge_of(line: &Line<'_>) -> (i8, Presence) {
match line.numbers {
Some(numbers) => numbers.charge,
None => charge_in(line.text),
}
}
pub(in crate::reader) fn charge_in(text: &str) -> (i8, Presence) {
let field = fixed::text(text, 79, 80);
let mut magnitude = None;
let mut sign = None;
for character in field.chars() {
match character {
'+' => sign = Some(1i8),
'-' => sign = Some(-1i8),
digit => magnitude = digit.to_digit(10).and_then(|d| i8::try_from(d).ok()),
}
}
match (magnitude, sign) {
(Some(value), Some(sign)) => (value * sign, Presence::Present),
_ => (0, Presence::Unknown),
}
}