rust_lodash/utils/
error.rs1#[derive(Debug, Clone, PartialEq)]
10pub enum LodashError {
11 InvalidInput {
14 message: String
16 },
17
18 TypeConversion {
21 from: String,
23 to: String
25 },
26
27 IndexOutOfBounds {
30 index: usize,
32 size: usize
34 },
35
36 EmptyCollection,
38
39 InvalidPredicate {
42 message: String
44 },
45
46 #[cfg(feature = "async")]
48 AsyncError { message: String },
49
50 #[cfg(feature = "parallel")]
52 ParallelError { message: String },
53
54 #[cfg(feature = "wasm")]
56 WasmError { message: String },
57
58 Custom {
61 message: String
63 },
64}
65
66impl std::fmt::Display for LodashError {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 match self {
69 LodashError::InvalidInput { message } => {
70 write!(f, "Invalid input: {message}")
71 }
72 LodashError::TypeConversion { from, to } => {
73 write!(f, "Type conversion failed: {from} -> {to}")
74 }
75 LodashError::IndexOutOfBounds { index, size } => {
76 write!(f, "Index {index} is out of bounds for collection of size {size}")
77 }
78 LodashError::EmptyCollection => {
79 write!(f, "Operation requires non-empty collection")
80 }
81 LodashError::InvalidPredicate { message } => {
82 write!(f, "Invalid predicate function: {message}")
83 }
84 #[cfg(feature = "async")]
85 LodashError::AsyncError { message } => {
86 write!(f, "Async operation failed: {}", message)
87 }
88 #[cfg(feature = "parallel")]
89 LodashError::ParallelError { message } => {
90 write!(f, "Parallel operation failed: {}", message)
91 }
92 #[cfg(feature = "wasm")]
93 LodashError::WasmError { message } => {
94 write!(f, "WASM operation failed: {}", message)
95 }
96 LodashError::Custom { message } => {
97 write!(f, "Custom error: {message}")
98 }
99 }
100 }
101}
102
103impl std::error::Error for LodashError {}
104
105pub type Result<T> = std::result::Result<T, LodashError>;
107
108impl LodashError {
109 pub fn invalid_input(message: impl Into<String>) -> Self {
111 Self::InvalidInput {
112 message: message.into(),
113 }
114 }
115
116 pub fn type_conversion(from: impl Into<String>, to: impl Into<String>) -> Self {
118 Self::TypeConversion {
119 from: from.into(),
120 to: to.into(),
121 }
122 }
123
124 #[must_use]
126 pub fn index_out_of_bounds(index: usize, size: usize) -> Self {
127 Self::IndexOutOfBounds { index, size }
128 }
129
130 #[must_use]
132 pub fn empty_collection() -> Self {
133 Self::EmptyCollection
134 }
135
136 pub fn invalid_predicate(message: impl Into<String>) -> Self {
138 Self::InvalidPredicate {
139 message: message.into(),
140 }
141 }
142
143 pub fn custom(message: impl Into<String>) -> Self {
145 Self::Custom {
146 message: message.into(),
147 }
148 }
149
150 #[cfg(feature = "async")]
151 pub fn async_error(message: impl Into<String>) -> Self {
153 Self::AsyncError {
154 message: message.into(),
155 }
156 }
157
158 #[cfg(feature = "parallel")]
159 pub fn parallel_error(message: impl Into<String>) -> Self {
161 Self::ParallelError {
162 message: message.into(),
163 }
164 }
165
166 #[cfg(feature = "wasm")]
167 pub fn wasm_error(message: impl Into<String>) -> Self {
169 Self::WasmError {
170 message: message.into(),
171 }
172 }
173}
174
175pub trait IntoLodashError<T> {
177 fn into_lodash_error(self) -> Result<T>;
183}
184
185impl<T, E> IntoLodashError<T> for std::result::Result<T, E>
186where
187 E: std::fmt::Display,
188{
189 fn into_lodash_error(self) -> Result<T> {
190 self.map_err(|e| LodashError::custom(e.to_string()))
191 }
192}
193
194#[macro_export]
196macro_rules! lodash_error {
197 ($variant:ident, $($arg:expr),*) => {
198 LodashError::$variant {
199 $($arg),*
200 }
201 };
202}
203
204#[macro_export]
206macro_rules! lodash_try {
207 ($expr:expr) => {
208 match $expr {
209 Ok(val) => val,
210 Err(err) => return Err(err.into_lodash_error().unwrap_err()),
211 }
212 };
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn test_error_creation() {
221 let err = LodashError::invalid_input("test message");
222 assert!(matches!(err, LodashError::InvalidInput { .. }));
223 assert_eq!(err.to_string(), "Invalid input: test message");
224
225 let err = LodashError::type_conversion("String", "i32");
226 assert!(matches!(err, LodashError::TypeConversion { .. }));
227 assert_eq!(err.to_string(), "Type conversion failed: String -> i32");
228
229 let err = LodashError::index_out_of_bounds(5, 3);
230 assert!(matches!(err, LodashError::IndexOutOfBounds { .. }));
231 assert_eq!(err.to_string(), "Index 5 is out of bounds for collection of size 3");
232
233 let err = LodashError::empty_collection();
234 assert!(matches!(err, LodashError::EmptyCollection));
235 assert_eq!(err.to_string(), "Operation requires non-empty collection");
236 }
237
238 #[test]
239 fn test_error_conversion() {
240 let result: std::result::Result<i32, String> = Err("test error".to_string());
241 let lodash_result: Result<i32> = result.into_lodash_error();
242
243 assert!(lodash_result.is_err());
244 if let Err(LodashError::Custom { message }) = lodash_result {
245 assert_eq!(message, "test error");
246 } else {
247 panic!("Expected Custom error variant");
248 }
249 }
250}