datalogic_rs/logic/
error.rs

1//! Error types for logic operations.
2//!
3//! This module provides error types for operations involving logic expressions.
4
5use std::error::Error;
6use std::fmt;
7use std::result;
8
9/// A specialized Result type for logic operations.
10pub type Result<T> = result::Result<T, LogicError>;
11
12/// Errors that can occur during logic operations.
13#[derive(Debug, Clone, PartialEq)]
14pub enum LogicError {
15    /// Error parsing a logic expression from JSON.
16    ParseError {
17        /// The reason for the parsing failure.
18        reason: String,
19    },
20
21    /// Error accessing a variable.
22    VariableError {
23        /// The variable path that caused the error.
24        path: String,
25        /// The reason for the variable access failure.
26        reason: String,
27    },
28
29    /// Error indicating that an operator is not found.
30    OperatorNotFoundError {
31        /// The operator that was not found.
32        operator: String,
33    },
34
35    NaNError,
36
37    InvalidArgumentsError,
38
39    /// Error thrown by the throw operator.
40    ThrownError {
41        /// The type or value of the error.
42        r#type: String,
43    },
44
45    /// A custom error with a message.
46    Custom(String),
47}
48
49impl fmt::Display for LogicError {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        match self {
52            LogicError::ParseError { reason } => {
53                write!(f, "Parse error: {}", reason)
54            }
55            LogicError::VariableError { path, reason } => {
56                write!(f, "Variable '{}' error: {}", path, reason)
57            }
58            LogicError::NaNError => {
59                write!(f, "NaN error")
60            }
61            LogicError::InvalidArgumentsError => {
62                write!(f, "Invalid arguments error")
63            }
64            LogicError::ThrownError { r#type } => {
65                write!(f, "Thrown error: {}", r#type)
66            }
67            LogicError::Custom(msg) => {
68                write!(f, "{}", msg)
69            }
70            LogicError::OperatorNotFoundError { operator } => {
71                write!(f, "Operator '{}' not found", operator)
72            }
73        }
74    }
75}
76
77impl Error for LogicError {}
78
79/// Extension methods for Result<T, LogicError>.
80pub trait LogicResultExt<T> {
81    /// Adds context to an error with a custom message.
82    fn with_context<F>(self, f: F) -> Result<T>
83    where
84        F: FnOnce() -> String;
85}
86
87impl<T> LogicResultExt<T> for Result<T> {
88    fn with_context<F>(self, f: F) -> Result<T>
89    where
90        F: FnOnce() -> String,
91    {
92        self.map_err(|err| {
93            let context = f();
94            LogicError::Custom(format!("{}: {}", context, err))
95        })
96    }
97}
98
99impl LogicError {
100    /// Creates a parse error with the given reason.
101    pub fn parse_error(reason: impl Into<String>) -> Self {
102        LogicError::ParseError {
103            reason: reason.into(),
104        }
105    }
106
107    /// Creates a variable error with the given path and reason.
108    pub fn variable_error(path: impl Into<String>, reason: impl Into<String>) -> Self {
109        LogicError::VariableError {
110            path: path.into(),
111            reason: reason.into(),
112        }
113    }
114
115    /// Creates a thrown error with the given type.
116    pub fn thrown_error(r#type: impl Into<String>) -> Self {
117        LogicError::ThrownError {
118            r#type: r#type.into(),
119        }
120    }
121
122    /// Creates a custom error with the given message.
123    pub fn custom(message: impl Into<String>) -> Self {
124        LogicError::Custom(message.into())
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    #[test]
133    fn test_parse_error() {
134        let err = LogicError::ParseError {
135            reason: "unexpected token".to_string(),
136        };
137        assert_eq!(err.to_string(), "Parse error: unexpected token");
138    }
139
140    #[test]
141    fn test_variable_error() {
142        let err = LogicError::VariableError {
143            path: "user.age".to_string(),
144            reason: "not found".to_string(),
145        };
146        assert_eq!(err.to_string(), "Variable 'user.age' error: not found");
147    }
148
149    #[test]
150    fn test_with_context() {
151        let result: Result<()> = Err(LogicError::ParseError {
152            reason: "unexpected token".to_string(),
153        });
154
155        let result_with_context =
156            result.with_context(|| "Failed to parse logic expression".to_string());
157
158        assert!(result_with_context.is_err());
159        if let Err(err) = result_with_context {
160            if let LogicError::Custom(msg) = err {
161                assert_eq!(
162                    msg,
163                    "Failed to parse logic expression: Parse error: unexpected token"
164                );
165            } else {
166                panic!("Expected Custom error variant");
167            }
168        }
169    }
170}