1use thiserror::Error;
4
5#[derive(Debug, Clone, Error)]
6#[non_exhaustive]
7pub enum DravyaError {
8 #[error("invalid material: {0}")]
9 InvalidMaterial(String),
10 #[error("invalid stress: {0}")]
11 InvalidStress(String),
12 #[error("invalid strain: {0}")]
13 InvalidStrain(String),
14 #[error("yield exceeded: {0}")]
15 YieldExceeded(String),
16 #[error("solver did not converge: {method} after {iterations} iterations")]
17 SolverNoConvergence {
18 method: &'static str,
19 iterations: usize,
20 },
21 #[error("division by zero: {0}")]
22 DivisionByZero(&'static str),
23 #[error("invalid parameter: {name} = {value} ({reason})")]
24 InvalidParameter {
25 name: &'static str,
26 value: f64,
27 reason: &'static str,
28 },
29}
30
31pub type Result<T> = std::result::Result<T, DravyaError>;
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 #[test]
38 fn error_display() {
39 let e = DravyaError::YieldExceeded("steel failed".into());
40 assert!(e.to_string().contains("steel failed"));
41 }
42
43 #[test]
44 fn division_by_zero_display() {
45 let e = DravyaError::DivisionByZero("zero modulus");
46 assert_eq!(e.to_string(), "division by zero: zero modulus");
47 }
48
49 #[test]
50 fn invalid_parameter_display() {
51 let e = DravyaError::InvalidParameter {
52 name: "poisson_ratio",
53 value: -2.0,
54 reason: "must be between -1 and 0.5",
55 };
56 assert!(e.to_string().contains("poisson_ratio"));
57 assert!(e.to_string().contains("-2"));
58 }
59
60 #[test]
61 fn solver_no_convergence_display() {
62 let e = DravyaError::SolverNoConvergence {
63 method: "newton_raphson",
64 iterations: 50,
65 };
66 assert!(e.to_string().contains("newton_raphson"));
67 assert!(e.to_string().contains("50"));
68 }
69
70 #[test]
71 fn error_is_clone() {
72 let e = DravyaError::SolverNoConvergence {
73 method: "test",
74 iterations: 10,
75 };
76 let e2 = e.clone();
77 assert_eq!(e.to_string(), e2.to_string());
78 }
79}