use ifc_model::{EntityId, ModelError};
use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum StepError {
#[error("not a STEP physical file: {0}")]
NotStep(String),
#[error("syntax error at byte {offset}: {detail}")]
Syntax {
offset: usize,
detail: String,
},
#[error("entity record without an id at byte {offset}")]
MissingEntityId {
offset: usize,
},
#[error("syntax error at byte {offset}: REAL `{token}` has no decimal point (ISO 10303-21 requires one)")]
RealWithoutDecimalPoint {
offset: usize,
token: String,
},
#[error("entity #{entity} slot {slot} contains a non-finite REAL")]
NonFiniteReal {
entity: EntityId,
slot: usize,
},
#[error("io error: {0}")]
Io(String),
}
impl StepError {
pub(crate) fn from_step(input: &[u8], error: openbim_step::StepError) -> Self {
if error.is_real_without_point() {
let span = error.span();
if let Some(token) = input.get(span.start..span.end) {
return Self::RealWithoutDecimalPoint {
offset: span.start,
token: String::from_utf8_lossy(token).into_owned(),
};
}
}
error.into()
}
}
impl From<openbim_step::StepError> for StepError {
fn from(error: openbim_step::StepError) -> Self {
if error.is_not_step() {
Self::NotStep(error.detail().to_owned())
} else {
Self::Syntax {
offset: error.span().start,
detail: error.detail().to_owned(),
}
}
}
}
impl From<StepError> for ModelError {
fn from(error: StepError) -> Self {
match error {
StepError::NotStep(detail) => ModelError::WrongFormat {
expected: "STEP",
detail,
},
StepError::Syntax { offset, detail } => ModelError::Syntax { offset, detail },
StepError::MissingEntityId { offset } => ModelError::Syntax {
offset,
detail: "entity record without an id".into(),
},
StepError::RealWithoutDecimalPoint { offset, token } => ModelError::Syntax {
offset,
detail: format!(
"REAL `{token}` has no decimal point (ISO 10303-21 requires one; \
a lenient read accepts it)"
),
},
StepError::NonFiniteReal { entity, slot } => ModelError::Write(format!(
"entity #{entity} slot {slot} contains a non-finite REAL"
)),
StepError::Io(message) => ModelError::Io(message),
}
}
}