1use std::fmt;
2use std::num::{ParseFloatError, ParseIntError};
3
4#[derive(Debug)]
5pub enum ParseError {
6 IncompleteHeader,
7 IncompleteFrame,
8 IncompleteVelocitySection,
9 InvalidVectorLength {
10 expected: usize,
11 found: usize,
12 },
13 InvalidNumberFormat(String),
14 MissingSpecVersion,
15 UnsupportedSpecVersion(u32),
16 InvalidMetadataJson(String),
17 IncompleteForceSection,
18 IncompleteEnergySection,
19 IncompleteSection(String),
21 UnknownSection(String),
22 ValidationError(String),
23 NonFiniteValue(String),
26 InvalidFixedFlag(String),
28 InvalidCount(String),
32 InvalidUnits(String),
37 UnsupportedVersion(u32),
40 IndexOutOfBounds {
47 index: usize,
48 len: usize,
49 },
50 MassMismatch {
55 symbol: String,
56 first_mass: f64,
57 found_mass: f64,
58 atom_index: usize,
59 },
60}
61
62impl fmt::Display for ParseError {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 match self {
65 ParseError::IncompleteHeader => {
66 write!(f, "file ended unexpectedly while parsing frame header")
67 }
68 ParseError::IncompleteFrame => {
69 write!(f, "file ended unexpectedly while reading atom data")
70 }
71 ParseError::IncompleteVelocitySection => {
72 write!(f, "file ended unexpectedly while reading velocity section")
73 }
74 ParseError::InvalidVectorLength { expected, found } => {
75 write!(f, "expected {expected} values on line, found {found}")
76 }
77 ParseError::InvalidNumberFormat(msg) => {
78 write!(f, "invalid number format: {msg}")
79 }
80 ParseError::MissingSpecVersion => {
81 write!(
82 f,
83 "line 2 must be a JSON object containing \"con_spec_version\""
84 )
85 }
86 ParseError::UnsupportedSpecVersion(v) | ParseError::UnsupportedVersion(v) => {
87 write!(f, "unsupported con_spec_version: {v}")
88 }
89 ParseError::InvalidMetadataJson(msg) => {
90 write!(f, "invalid JSON metadata on line 2: {msg}")
91 }
92 ParseError::IncompleteForceSection => {
93 write!(f, "file ended unexpectedly while reading force section")
94 }
95 ParseError::IncompleteEnergySection => {
96 write!(f, "file ended unexpectedly while reading energy section")
97 }
98 ParseError::IncompleteSection(name) => {
99 write!(f, "file ended unexpectedly while reading {name} section")
100 }
101 ParseError::UnknownSection(name) => {
102 write!(f, "unknown section type in metadata: {name}")
103 }
104 ParseError::ValidationError(msg) => {
105 write!(f, "CON validation failed: {msg}")
106 }
107 ParseError::NonFiniteValue(token) => {
108 write!(f, "non-finite value: {token}")
109 }
110 ParseError::InvalidFixedFlag(msg) => {
111 write!(f, "invalid fixed flag: {msg}")
112 }
113 ParseError::InvalidCount(msg) => {
114 write!(f, "invalid count: {msg}")
115 }
116 ParseError::InvalidUnits(msg) => {
117 write!(f, "invalid units: {msg}")
118 }
119 ParseError::IndexOutOfBounds { index, len } => {
120 write!(
121 f,
122 "atom index {index} is out of bounds (builder holds {len} atoms)"
123 )
124 }
125 ParseError::MassMismatch {
126 symbol,
127 first_mass,
128 found_mass,
129 atom_index,
130 } => {
131 write!(
132 f,
133 "atoms of type {symbol} have inconsistent masses: first {first_mass}, atom {atom_index} has {found_mass} (CON stores one mass per type)"
134 )
135 }
136 }
137 }
138}
139
140impl std::error::Error for ParseError {}
141
142impl ParseError {
143 pub fn class_name(&self) -> &'static str {
145 match self {
146 ParseError::IncompleteHeader => "IncompleteHeader",
147 ParseError::IncompleteFrame => "IncompleteFrame",
148 ParseError::IncompleteVelocitySection => "IncompleteVelocitySection",
149 ParseError::InvalidVectorLength { .. } => "InvalidVectorLength",
150 ParseError::InvalidNumberFormat(_) => "InvalidNumberFormat",
151 ParseError::MissingSpecVersion => "MissingSpecVersion",
152 ParseError::UnsupportedSpecVersion(_) | ParseError::UnsupportedVersion(_) => {
153 "UnsupportedVersion"
154 }
155 ParseError::InvalidMetadataJson(_) => "InvalidMetadataJson",
156 ParseError::IncompleteForceSection => "IncompleteForceSection",
157 ParseError::IncompleteEnergySection => "IncompleteEnergySection",
158 ParseError::IncompleteSection(_) => "IncompleteSection",
159 ParseError::UnknownSection(_) => "UnknownSection",
160 ParseError::ValidationError(_) => "ValidationError",
161 ParseError::IndexOutOfBounds { .. } => "IndexOutOfBounds",
162 ParseError::MassMismatch { .. } => "MassMismatch",
163 ParseError::NonFiniteValue(_) => "NonFiniteValue",
164 ParseError::InvalidFixedFlag(_) => "InvalidFixedFlag",
165 ParseError::InvalidCount(_) => "InvalidCount",
166 ParseError::InvalidUnits(_) => "InvalidUnits",
167 }
168 }
169
170 pub fn line(&self) -> u32 {
175 match self {
176 ParseError::MissingSpecVersion
177 | ParseError::InvalidMetadataJson(_)
178 | ParseError::UnsupportedSpecVersion(_)
179 | ParseError::UnsupportedVersion(_) => 2,
180 _ => 0,
181 }
182 }
183}
184
185impl From<ParseFloatError> for ParseError {
186 fn from(e: ParseFloatError) -> Self {
187 ParseError::InvalidNumberFormat(e.to_string())
188 }
189}
190
191impl From<ParseIntError> for ParseError {
192 fn from(e: ParseIntError) -> Self {
193 ParseError::InvalidNumberFormat(e.to_string())
194 }
195}
196
197impl From<serde_json::Error> for ParseError {
198 fn from(e: serde_json::Error) -> Self {
199 ParseError::InvalidMetadataJson(e.to_string())
200 }
201}