blas_array2/util/
blas_error.rs

1#[cfg(feature = "std")]
2extern crate std;
3
4extern crate alloc;
5
6use alloc::string::String;
7use core::num::TryFromIntError;
8use derive_builder::UninitializedFieldError;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum BLASError {
12    OverflowDimension(String),
13    InvalidDim(String),
14    InvalidFlag(String),
15    FailedCheck(String),
16    UninitializedField(&'static str),
17    ExplicitCopy(String),
18    Miscellaneous(String),
19    RuntimeError(String),
20}
21
22/* #region impl BLASError */
23
24#[cfg(feature = "std")]
25impl std::error::Error for BLASError {}
26
27impl From<UninitializedFieldError> for BLASError {
28    fn from(e: UninitializedFieldError) -> BLASError {
29        BLASError::UninitializedField(e.field_name())
30    }
31}
32
33impl From<TryFromIntError> for BLASError {
34    fn from(_: TryFromIntError) -> BLASError {
35        BLASError::OverflowDimension(String::from("TryFromIntError"))
36    }
37}
38
39impl core::fmt::Display for BLASError {
40    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
41        write!(f, "{:?}", self)
42    }
43}
44
45/* #endregion */
46
47/* #region macros */
48
49#[macro_export]
50macro_rules! blas_assert {
51    ($cond:expr, $errtype:ident, $($arg:tt)*) => {
52        if $cond {
53            Ok(())
54        } else {
55            extern crate alloc;
56            use alloc::string::String;
57            Err(BLASError::$errtype(String::from(concat!(
58                file!(), ":", line!(), ": ", "BLASError::", stringify!($errtype), " : ",
59                $($arg),*, ": ", stringify!($cond)
60            ))))
61        }
62    };
63    ($cond:expr, $errtype:ident) => {
64        if $cond {
65            Ok(())
66        } else {
67            extern crate alloc;
68            use alloc::string::String;
69            Err(BLASError::$errtype(String::from(concat!(
70                file!(), ":", line!(), ": ", "BLASError::", stringify!($errtype), " : ",
71                stringify!($cond)
72            ))))
73        }
74    };
75}
76
77#[macro_export]
78macro_rules! blas_assert_eq {
79    ($a:expr, $b:expr, $errtype:ident) => {
80        if $a == $b {
81            Ok(())
82        } else {
83            extern crate alloc;
84            use alloc::string::String;
85            use core::fmt::Write;
86            let mut s = String::from(concat!(
87                file!(),
88                ":",
89                line!(),
90                ": ",
91                "BLASError::",
92                stringify!($errtype),
93                " : "
94            ));
95            write!(s, "{:?} = {:?} not equal to {:?} = {:?}", stringify!($a), $a, stringify!($b), $b)
96                .unwrap();
97            Err(BLASError::$errtype(s))
98        }
99    };
100}
101
102#[macro_export]
103macro_rules! blas_raise {
104    ($errtype:ident) => {{
105        extern crate alloc;
106        use alloc::string::String;
107        Err(BLASError::$errtype(String::from(concat!(
108            file!(), ":", line!(), ": ", "BLASError::", stringify!($errtype)
109        ))))
110    }};
111    ($errtype:ident, $($arg:tt)*) => {{
112        extern crate alloc;
113        use alloc::string::String;
114        Err(BLASError::$errtype(String::from(concat!(
115            file!(), ":", line!(), ": ", "BLASError::", stringify!($errtype), " : ",
116            $($arg),*
117        ))))
118    }};
119}
120
121#[macro_export]
122macro_rules! blas_invalid {
123    ($word:expr) => {{
124        extern crate alloc;
125        use alloc::string::String;
126        use core::fmt::Write;
127        let mut s = String::from(concat!(file!(), ":", line!(), ": ", "BLASError::InvalidFlag", " : "));
128        write!(s, "{:?} = {:?}", stringify!($word), $word).unwrap();
129        Err(BLASError::InvalidFlag(s))
130    }};
131}
132
133/* #endregion */
134
135/* #region macros (warning) */
136
137#[macro_export]
138macro_rules! blas_warn_layout_clone {
139    ($array:expr) => {{
140        #[cfg(feature = "std")]
141        extern crate std;
142
143        if cfg!(all(feature = "std", feature = "warn_on_copy")) {
144            std::eprintln!(
145                "Warning: Copying array due to non-standard layout, shape={:?}, strides={:?}",
146                $array.shape(),
147                $array.strides()
148            );
149            Result::<(), BLASError>::Ok(())
150        } else if cfg!(feature = "error_on_copy") {
151            blas_raise!(ExplicitCopy)
152        } else {
153            Result::<(), BLASError>::Ok(())
154        }
155    }};
156    ($array:expr, $msg:tt) => {{
157        #[cfg(feature = "std")]
158        extern crate std;
159
160        if cfg!(all(feature = "std", feature = "warn_on_copy")) {
161            std::eprintln!("Warning: {:?}, shape={:?}, strides={:?}", $msg, $array.shape(), $array.strides());
162            Result::<(), BLASError>::Ok(())
163        } else if cfg!(feature = "error_on_copy") {
164            blas_raise!(ExplicitCopy)
165        } else {
166            Result::<(), BLASError>::Ok(())
167        }
168    }};
169}
170
171/* #endregion */
172
173// Following test is assisted by DeepSeek
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn test_from_uninitialized_field_error() {
180        let error = UninitializedFieldError::new("field_name");
181        let blas_error: BLASError = error.into();
182        assert_eq!(blas_error, BLASError::UninitializedField("field_name"));
183    }
184
185    #[test]
186    fn test_from_try_from_int_error() {
187        let error: Result<i32, _> = (1000000000000 as usize).try_into();
188        let blas_error: BLASError = error.unwrap_err().into();
189        assert_eq!(blas_error, BLASError::OverflowDimension("TryFromIntError".to_string()));
190    }
191
192    #[test]
193    fn test_blas_assert_macro_with_args() {
194        let result = blas_assert!(false, InvalidFlag, "test_condition");
195        if let Err(BLASError::InvalidFlag(msg)) = result {
196            assert!(msg.contains("BLASError::InvalidFlag"));
197            assert!(msg.contains("test_condition"));
198        } else {
199            panic!("Expected BLASError::InvalidFlag");
200        }
201    }
202
203    #[test]
204    fn test_blas_assert_macro_without_args() {
205        let result = blas_assert!(false, InvalidFlag);
206        if let Err(BLASError::InvalidFlag(msg)) = result {
207            assert!(msg.contains("BLASError::InvalidFlag"));
208        } else {
209            panic!("Expected BLASError::InvalidFlag");
210        }
211    }
212
213    #[test]
214    fn test_blas_assert_eq_macro() {
215        let result = blas_assert_eq!(1, 2, InvalidFlag);
216        if let Err(BLASError::InvalidFlag(msg)) = result {
217            assert!(msg.contains("BLASError::InvalidFlag"));
218            assert!(msg.contains(r#""1" = 1 not equal to "2" = 2"#));
219        } else {
220            panic!("Expected BLASError::InvalidFlag");
221        }
222    }
223
224    #[test]
225    fn test_blas_raise_macro_without_args() {
226        let result: Result<(), BLASError> = blas_raise!(InvalidFlag);
227        if let Err(BLASError::InvalidFlag(msg)) = result {
228            assert!(msg.contains("BLASError::InvalidFlag"));
229        } else {
230            panic!("Expected BLASError::InvalidFlag");
231        }
232    }
233
234    #[test]
235    fn test_blas_raise_macro_with_args() {
236        let result: Result<(), BLASError> = blas_raise!(InvalidFlag, "test_message");
237        if let Err(BLASError::InvalidFlag(msg)) = result {
238            assert!(msg.contains("BLASError::InvalidFlag"));
239            assert!(msg.contains("test_message"));
240        } else {
241            panic!("Expected BLASError::InvalidFlag");
242        }
243    }
244
245    #[test]
246    fn test_blas_invalid_macro() {
247        let word = 1;
248        let result: Result<(), BLASError> = blas_invalid!(word);
249        if let Err(BLASError::InvalidFlag(msg)) = result {
250            assert!(msg.contains("BLASError::InvalidFlag"));
251            assert!(msg.contains(r#""word" = 1"#));
252        } else {
253            panic!("Expected BLASError::InvalidFlag");
254        }
255    }
256}