Skip to main content

fast_mesh_ops/
error.rs

1//! Errors reported by repair operations.
2
3use std::fmt;
4
5use fast_mesh_query::QueryError;
6use fast_mesh_store::StoreError;
7
8/// Why a repair operation could not run.
9///
10/// Every operation computes and validates its whole plan before writing, so
11/// an error leaves the mesh as it was, except where the store's own error says
12/// otherwise ([`StoreError::TransactionPoisoned`]).
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum OpsError {
15    /// The store failed, including running out of memory
16    /// ([`StoreError::OutOfMemory`]).
17    Store(StoreError),
18    /// A query used by the operation failed.
19    Query(QueryError),
20    /// An argument was invalid; the message says which and why.
21    InvalidInput(&'static str),
22    /// A requested boundary loop no longer exists in the mesh.
23    StaleLoops,
24}
25
26impl From<StoreError> for OpsError {
27    fn from(e: StoreError) -> Self {
28        OpsError::Store(e)
29    }
30}
31
32/// A query running out of memory becomes [`OpsError::Store`] with
33/// [`StoreError::OutOfMemory`], like every other allocation failure here.
34impl From<QueryError> for OpsError {
35    fn from(e: QueryError) -> Self {
36        match e {
37            QueryError::OutOfMemory => OpsError::Store(StoreError::OutOfMemory),
38            e => OpsError::Query(e),
39        }
40    }
41}
42
43impl fmt::Display for OpsError {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        match self {
46            OpsError::Store(e) => write!(f, "store error: {e}"),
47            OpsError::Query(e) => write!(f, "query error: {e}"),
48            OpsError::InvalidInput(what) => write!(f, "invalid input: {what}"),
49            OpsError::StaleLoops => {
50                f.write_str("a requested boundary loop no longer matches the mesh")
51            }
52        }
53    }
54}
55
56impl std::error::Error for OpsError {
57    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
58        match self {
59            OpsError::Store(e) => Some(e),
60            OpsError::Query(e) => Some(e),
61            _ => None,
62        }
63    }
64}
65
66/// `Result` with [`OpsError`] as the error type.
67pub type Result<T> = std::result::Result<T, OpsError>;
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use std::error::Error;
73
74    #[test]
75    fn conversions_display_and_source() {
76        let e: OpsError = StoreError::OutOfMemory.into();
77        assert_eq!(e, OpsError::Store(StoreError::OutOfMemory));
78        assert_eq!(e.to_string(), "store error: out of memory");
79        assert!(e.source().is_some());
80        let q: OpsError = QueryError::StaleBvh.into();
81        assert_eq!(q, OpsError::Query(QueryError::StaleBvh));
82        assert!(q.source().is_some());
83        let oom: OpsError = QueryError::OutOfMemory.into();
84        assert_eq!(oom, OpsError::Store(StoreError::OutOfMemory));
85        assert_eq!(
86            OpsError::InvalidInput("no bound").to_string(),
87            "invalid input: no bound"
88        );
89        assert!(OpsError::StaleLoops.source().is_none());
90    }
91}