Skip to main content

readcon_core/
error.rs

1use std::fmt;
2use std::num::{ParseFloatError, ParseIntError};
3
4#[derive(Debug)]
5pub enum ParseError {
6    IncompleteHeader,
7    IncompleteFrame,
8    IncompleteVelocitySection,
9    InvalidVectorLength { expected: usize, found: usize },
10    InvalidNumberFormat(String),
11    MissingSpecVersion,
12    UnsupportedSpecVersion(u32),
13    InvalidMetadataJson(String),
14    IncompleteForceSection,
15    IncompleteEnergySection,
16    /// Declared optional section was incomplete or mislabeled.
17    IncompleteSection(String),
18    UnknownSection(String),
19    ValidationError(String),
20    /// An in-place builder mutation
21    /// (`ConFrameBuilder::set_atom_position` / `set_atom_velocity` /
22    /// `set_atom_force` / `set_atom_energy` / `set_atom_fixed` /
23    /// `set_atom_mass` / clear_*) was called with an atom index past
24    /// the current length. Surfaces as `IndexError` in PyO3 and as
25    /// `RKR_STATUS_INDEX_OUT_OF_BOUNDS` over the C ABI.
26    IndexOutOfBounds { index: usize, len: usize },
27}
28
29impl fmt::Display for ParseError {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            ParseError::IncompleteHeader => {
33                write!(f, "file ended unexpectedly while parsing frame header")
34            }
35            ParseError::IncompleteFrame => {
36                write!(f, "file ended unexpectedly while reading atom data")
37            }
38            ParseError::IncompleteVelocitySection => {
39                write!(f, "file ended unexpectedly while reading velocity section")
40            }
41            ParseError::InvalidVectorLength { expected, found } => {
42                write!(f, "expected {expected} values on line, found {found}")
43            }
44            ParseError::InvalidNumberFormat(msg) => {
45                write!(f, "invalid number format: {msg}")
46            }
47            ParseError::MissingSpecVersion => {
48                write!(
49                    f,
50                    "line 1 must be a JSON object containing \"con_spec_version\""
51                )
52            }
53            ParseError::UnsupportedSpecVersion(v) => {
54                write!(f, "unsupported con_spec_version: {v}")
55            }
56            ParseError::InvalidMetadataJson(msg) => {
57                write!(f, "invalid JSON metadata on line 1: {msg}")
58            }
59            ParseError::IncompleteForceSection => {
60                write!(f, "file ended unexpectedly while reading force section")
61            }
62            ParseError::IncompleteEnergySection => {
63                write!(f, "file ended unexpectedly while reading energy section")
64            }
65            ParseError::IncompleteSection(name) => {
66                write!(f, "file ended unexpectedly while reading {name} section")
67            }
68            ParseError::UnknownSection(name) => {
69                write!(f, "unknown section type in metadata: {name}")
70            }
71            ParseError::ValidationError(msg) => {
72                write!(f, "CON validation failed: {msg}")
73            }
74            ParseError::IndexOutOfBounds { index, len } => {
75                write!(
76                    f,
77                    "atom index {index} is out of bounds (builder holds {len} atoms)"
78                )
79            }
80        }
81    }
82}
83
84impl std::error::Error for ParseError {}
85
86impl From<ParseFloatError> for ParseError {
87    fn from(e: ParseFloatError) -> Self {
88        ParseError::InvalidNumberFormat(e.to_string())
89    }
90}
91
92impl From<ParseIntError> for ParseError {
93    fn from(e: ParseIntError) -> Self {
94        ParseError::InvalidNumberFormat(e.to_string())
95    }
96}
97
98impl From<serde_json::Error> for ParseError {
99    fn from(e: serde_json::Error) -> Self {
100        ParseError::InvalidMetadataJson(e.to_string())
101    }
102}