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}