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#[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#[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#[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#[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}