1use std::{fmt::Debug, fmt::Display};
2
3use crate::{Location, colormap::NumberRange, error::InvalidData};
4
5#[derive(Debug, Clone, PartialEq, thiserror::Error)]
7pub enum Reason {
8 #[error("must be finite")]
10 NotFinite,
11 #[error("must be greater than zero")]
13 NotGreaterThanZero,
14 #[error("must be a unit vector but {0:?} length is {1}")]
16 NotUnitVector([f64; 3], f64),
17 #[error("vectors are not orthogonal: {0:?} {1:?}")]
19 NotOrthogonal([f64; 3], [f64; 3]),
20 #[error("sub-block counts {0:?} must be powers of two for octree mode")]
23 OctreeNotPowerOfTwo([u32; 3]),
24 #[error("grid count {0:?} exceeds maximum of 4,294,967,295")]
26 GridTooLarge(Vec<u64>),
27 #[error("is {0:?} which is not valid on {1} geometry")]
29 AttrLocationWrongForGeom(Location, &'static str),
30 #[error("is {0:?} which is not valid on {1} attributes")]
32 AttrLocationWrongForAttr(Location, &'static str),
33 #[error("length {0} does not match geometry ({1})")]
35 AttrLengthMismatch(u64, u64),
36 #[error("minimum is greater than maximum in {0}")]
38 MinMaxOutOfOrder(NumberRange),
39 #[error("array contains invalid data: {0}")]
41 InvalidData(InvalidData),
42 #[error("refers to non-existent archive member '{0}'")]
44 ZipMemberMissing(String),
45 #[error("must be unique but {0} is repeated")]
47 NotUnique(String),
48 #[error("contains duplicate of {0}")]
50 SoftNotUnique(String),
51 #[error("{0} more errors")]
53 MoreErrors(u32),
54 #[error("{0} more warnings")]
56 MoreWarnings(u32),
57}
58
59impl Reason {
60 pub fn is_error(&self) -> bool {
62 !matches!(self, Self::SoftNotUnique(_) | Reason::MoreWarnings(_))
63 }
64}
65
66#[derive(Debug, Clone, PartialEq)]
68pub struct Problem {
69 pub reason: Reason,
71 pub ty: &'static str,
73 pub field: Option<&'static str>,
75 pub name: Option<String>,
77}
78
79impl Problem {
80 pub fn is_error(&self) -> bool {
82 self.reason.is_error()
83 }
84}
85
86impl Display for Problem {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 let severity = if self.reason.is_error() {
90 "Error"
91 } else {
92 "Warning"
93 };
94 write!(f, "{severity}: '{}", self.ty)?;
95 if let Some(field) = self.field {
96 write!(f, "::{field}'")?;
97 } else {
98 write!(f, "'")?;
99 }
100 write!(f, " {}", self.reason)?;
101 if let Some(name) = &self.name {
102 write!(f, ", inside '{name}'")?;
103 }
104 Ok(())
105 }
106}
107
108#[derive(Debug, Default, Clone, PartialEq)]
110pub struct Problems(Vec<Problem>);
111
112impl Problems {
113 pub fn is_empty(&self) -> bool {
115 self.0.is_empty()
116 }
117
118 pub fn len(&self) -> usize {
120 self.0.len()
121 }
122
123 pub fn into_vec(self) -> Vec<Problem> {
125 self.0
126 }
127
128 pub fn iter(&self) -> impl Iterator<Item = &Problem> {
130 self.0.iter()
131 }
132
133 pub(crate) fn into_result(self) -> Result<Self, Self> {
135 if self.0.iter().any(|p| p.is_error()) {
136 Err(self)
137 } else {
138 Ok(self)
139 }
140 }
141
142 pub(crate) fn push(
143 &mut self,
144 reason: Reason,
145 ty: &'static str,
146 field: Option<&'static str>,
147 name: Option<String>,
148 ) {
149 self.0.push(Problem {
150 reason,
151 ty,
152 field,
153 name,
154 })
155 }
156}
157
158impl Display for Problems {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 let n_errors = self.0.iter().filter(|p| p.reason.is_error()).count();
162 let n_warnings = self.0.len() - n_errors;
163 match (n_errors, n_warnings) {
164 (0, 0) => write!(f, "OMF validation passed")?,
165 (0, _) => write!(f, "OMF validation passed with warnings:")?,
166 _ => write!(f, "OMF validation failed:")?,
167 }
168 for problem in self {
169 write!(f, "\n {problem}")?;
170 }
171 Ok(())
172 }
173}
174
175impl std::error::Error for Problems {}
176
177impl IntoIterator for Problems {
178 type Item = Problem;
179 type IntoIter = std::vec::IntoIter<Problem>;
180
181 fn into_iter(self) -> Self::IntoIter {
182 self.0.into_iter()
183 }
184}
185
186impl<'a> IntoIterator for &'a Problems {
187 type Item = &'a Problem;
188 type IntoIter = std::slice::Iter<'a, Problem>;
189
190 fn into_iter(self) -> Self::IntoIter {
191 self.0.iter()
192 }
193}
194
195impl From<Problems> for Vec<Problem> {
196 fn from(value: Problems) -> Self {
197 value.into_vec()
198 }
199}