Skip to main content

async_jsonata_rust/
error.rs

1use std::collections::BTreeMap;
2use std::fmt;
3
4use serde_json::Value;
5
6use crate::parser::ParserError;
7use crate::types::JsonError;
8
9/// Unified crate error used by stable public APIs.
10///
11/// # Examples
12/// ```rust
13/// let err = async_jsonata_rust::Error::new("D3040", "Sqrt domain error");
14/// assert_eq!(err.code(), "D3040");
15/// ```
16#[derive(Debug, Clone)]
17pub struct Error {
18    code: String,
19    message: String,
20    position: Option<usize>,
21    token: Option<Value>,
22    value: Option<Value>,
23    remaining: Option<Vec<Value>>,
24    context: BTreeMap<String, Value>,
25}
26
27impl Error {
28    /// Creates a new error with JSONata-compatible code.
29    ///
30    /// # Examples
31    /// ```rust
32    /// let err = async_jsonata_rust::Error::new("S0201", "Unexpected token");
33    /// assert_eq!(err.code(), "S0201");
34    /// ```
35    pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
36        Self {
37            code: code.into(),
38            message: message.into(),
39            position: None,
40            token: None,
41            value: None,
42            remaining: None,
43            context: BTreeMap::new(),
44        }
45    }
46
47    /// Creates a parser error from parser internals.
48    ///
49    /// # Examples
50    /// ```rust
51    /// let parse_error = async_jsonata_rust::parse_expression("1+", false).unwrap_err();
52    /// let err = async_jsonata_rust::Error::from(parse_error);
53    /// assert!(!err.code().is_empty());
54    /// ```
55    pub fn parser(err: ParserError) -> Self {
56        let mut out = Self::new(err.code, "parser error");
57        out.position = Some(err.position);
58        out.token = err.token;
59        out.value = err.value;
60        out.remaining = err.remaining;
61        out
62    }
63
64    /// Creates a runtime error from evaluator/function internals.
65    ///
66    /// # Examples
67    /// ```rust
68    /// let runtime = async_jsonata_rust::JsonError::new("D3040", "Sqrt domain error");
69    /// let err = async_jsonata_rust::Error::from(runtime);
70    /// assert_eq!(err.code(), "D3040");
71    /// ```
72    pub fn runtime(err: JsonError) -> Self {
73        Self::new(err.code, err.message)
74    }
75
76    /// Creates a not-implemented error for incomplete features.
77    ///
78    /// # Examples
79    /// ```rust
80    /// let err = async_jsonata_rust::Error::not_implemented("evaluator pending");
81    /// assert_eq!(err.code(), "E0001");
82    /// ```
83    pub fn not_implemented(message: impl Into<String>) -> Self {
84        Self::new("E0001", message)
85    }
86
87    /// Adds named context field.
88    ///
89    /// # Examples
90    /// ```rust
91    /// let err = async_jsonata_rust::Error::new("E1", "oops")
92    ///     .with_context("field", serde_json::Value::String("value".into()));
93    /// assert!(err.context().contains_key("field"));
94    /// ```
95    pub fn with_context(mut self, key: impl Into<String>, value: Value) -> Self {
96        self.context.insert(key.into(), value);
97        self
98    }
99
100    /// Returns JSONata error code (`D3040`, `S0201`, ...).
101    pub fn code(&self) -> &str {
102        &self.code
103    }
104
105    /// Returns human-readable message.
106    pub fn message(&self) -> &str {
107        &self.message
108    }
109
110    /// Returns parser position if known.
111    pub fn position(&self) -> Option<usize> {
112        self.position
113    }
114
115    /// Returns token payload if known.
116    pub fn token(&self) -> Option<&Value> {
117        self.token.as_ref()
118    }
119
120    /// Returns parser value payload if known.
121    pub fn value(&self) -> Option<&Value> {
122        self.value.as_ref()
123    }
124
125    /// Returns unparsed trailing token payload if known.
126    pub fn remaining(&self) -> Option<&[Value]> {
127        self.remaining.as_deref()
128    }
129
130    /// Returns structured context fields.
131    pub fn context(&self) -> &BTreeMap<String, Value> {
132        &self.context
133    }
134}
135
136impl fmt::Display for Error {
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        write!(f, "{}: {}", self.code, self.message)
139    }
140}
141
142impl std::error::Error for Error {}
143
144impl From<ParserError> for Error {
145    fn from(value: ParserError) -> Self {
146        Self::parser(value)
147    }
148}
149
150impl From<JsonError> for Error {
151    fn from(value: JsonError) -> Self {
152        Self::runtime(value)
153    }
154}