reifydb_type/error/
macro.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4/// Macro to create an Error from a diagnostic function call
5///
6/// Usage:
7/// - `error!(diagnostic_function(args))` - Creates an error without fragment
8/// - `error!(diagnostic_function(args), fragment)` - Creates an error with fragment
9///
10/// Expands to: `Error(diagnostic_function(args))` or
11/// `Error(diagnostic_function(args).with_fragment(fragment))`
12///
13/// Examples:
14/// - `error!(sequence_exhausted(Type::Uint8))`
15/// - `error!(sequence_exhausted(Type::Uint8), fragment)`
16#[macro_export]
17macro_rules! error {
18	($diagnostic:expr) => {
19		$crate::Error($diagnostic)
20	};
21	($diagnostic:expr, $fragment:expr) => {{
22		let mut diag = $diagnostic;
23		diag.with_fragment($crate::IntoFragment::into_fragment($fragment).into_owned());
24		$crate::Error(diag)
25	}};
26}
27
28/// Macro to return an error from a diagnostic function call
29///
30/// Usage:
31/// - `return_error!(diagnostic_function(args))` - Returns an error without fragment
32/// - `return_error!(diagnostic_function(args), fragment)` - Returns an error with fragment
33///
34/// Expands to: `return Err(Error(diagnostic_function(args)))` or `return
35/// Err(Error(diagnostic_function(args).with_fragment(fragment)))`
36///
37/// Examples:
38/// - `return_error!(sequence_exhausted(Type::Uint8))`
39/// - `return_error!(sequence_exhausted(Type::Uint8), fragment)`
40#[macro_export]
41macro_rules! return_error {
42	($diagnostic:expr) => {
43		return Err($crate::Error($diagnostic))
44	};
45	($diagnostic:expr, $fragment:expr) => {{
46		let mut diag = $diagnostic;
47		diag.with_fragment($crate::IntoFragment::into_fragment($fragment).into_owned());
48		return Err($crate::Error(diag));
49	}};
50}
51
52/// Macro to create an Err(Error()) from a diagnostic function call
53///
54/// Usage:
55/// - `err!(diagnostic_function(args))` - Creates an Err without fragment
56/// - `err!(diagnostic_function(args), fragment)` - Creates an Err with fragment
57///
58/// Expands to: `Err(Error(diagnostic_function(args)))` or
59/// `Err(Error(diagnostic_function(args).with_fragment(fragment)))`
60///
61/// Examples:
62/// - `err!(sequence_exhausted(Type::Uint8))`
63/// - `err!(sequence_exhausted(Type::Uint8), fragment)`
64#[macro_export]
65macro_rules! err {
66	($diagnostic:expr) => {
67		Err($crate::Error($diagnostic))
68	};
69	($diagnostic:expr, $fragment:expr) => {{
70		let mut diag = $diagnostic;
71		diag.with_fragment($crate::IntoFragment::into_fragment($fragment).into_owned());
72		Err($crate::Error(diag))
73	}};
74}
75
76#[cfg(test)]
77mod tests {
78	use crate::{
79		OwnedFragment, StatementColumn, StatementLine, Type, error::diagnostic::sequence::sequence_exhausted,
80	};
81
82	#[test]
83	fn test_error_macro() {
84		// Test that error! macro creates correct Error type
85		let err = error!(sequence_exhausted(Type::Uint8));
86
87		// Verify it creates the correct Error type
88		assert!(matches!(err, crate::Error(_)));
89
90		// Test that the diagnostic is properly wrapped
91		let diagnostic = err.diagnostic();
92		assert!(diagnostic.message.contains("exhausted"));
93	}
94
95	#[test]
96	fn test_return_error_macro() {
97		fn test_fn() -> Result<(), crate::Error> {
98			return_error!(sequence_exhausted(Type::Uint8));
99		}
100
101		let result = test_fn();
102		assert!(result.is_err());
103
104		if let Err(err) = result {
105			let diagnostic = err.diagnostic();
106			assert!(diagnostic.message.contains("exhausted"));
107		}
108	}
109
110	#[test]
111	fn test_err_macro() {
112		// Test that err! macro creates correct Result type with Err
113		let result: Result<(), crate::Error> = err!(sequence_exhausted(Type::Uint8));
114
115		assert!(result.is_err());
116
117		if let Err(err) = result {
118			let diagnostic = err.diagnostic();
119			assert!(diagnostic.message.contains("exhausted"));
120		}
121	}
122
123	#[test]
124	fn test_error_macro_with_fragment() {
125		// Create a test fragment
126		let fragment = OwnedFragment::Statement {
127			line: StatementLine(42),
128			column: StatementColumn(10),
129			text: "test fragment".to_string(),
130		};
131
132		// Test that error! macro with fragment creates correct Error
133		// type
134		let err = error!(sequence_exhausted(Type::Uint8), fragment.clone());
135
136		// Verify it creates the correct Error type
137		assert!(matches!(err, crate::Error(_)));
138
139		// Test that the diagnostic has the origin set (via fragment)
140		let diagnostic = err.diagnostic();
141		let fragment = diagnostic.fragment();
142		assert!(fragment.is_some());
143		if let Some(OwnedFragment::Statement {
144			line,
145			column,
146			..
147		}) = fragment.as_ref()
148		{
149			assert_eq!(line.0, 42);
150			assert_eq!(column.0, 10);
151		}
152	}
153
154	#[test]
155	fn test_return_error_macro_with_fragment() {
156		fn test_fn() -> Result<(), crate::Error> {
157			let fragment = OwnedFragment::Statement {
158				line: StatementLine(100),
159				column: StatementColumn(25),
160				text: "error location".to_string(),
161			};
162			return_error!(sequence_exhausted(Type::Uint8), fragment);
163		}
164
165		let result = test_fn();
166		assert!(result.is_err());
167
168		if let Err(err) = result {
169			let diagnostic = err.diagnostic();
170			let fragment = diagnostic.fragment();
171			assert!(fragment.is_some());
172			if let Some(OwnedFragment::Statement {
173				line,
174				column,
175				..
176			}) = fragment.as_ref()
177			{
178				assert_eq!(line.0, 100);
179				assert_eq!(column.0, 25);
180			}
181		}
182	}
183
184	#[test]
185	fn test_err_macro_with_fragment() {
186		let fragment = OwnedFragment::Statement {
187			line: StatementLine(200),
188			column: StatementColumn(50),
189			text: "err fragment test".to_string(),
190		};
191
192		// Test that err! macro with fragment creates correct Result
193		// type with Err
194		let result: Result<(), crate::Error> = err!(sequence_exhausted(Type::Uint8), fragment);
195
196		assert!(result.is_err());
197
198		if let Err(err) = result {
199			let diagnostic = err.diagnostic();
200			let fragment = diagnostic.fragment();
201			assert!(fragment.is_some());
202			if let Some(OwnedFragment::Statement {
203				line,
204				column,
205				..
206			}) = fragment.as_ref()
207			{
208				assert_eq!(line.0, 200);
209				assert_eq!(column.0, 50);
210			}
211		}
212	}
213
214	#[test]
215	fn test_macros_with_closure_fragment() {
216		// Test with closure that returns OwnedFragment (implements
217		// IntoOwnedFragment)
218		let get_fragment = || OwnedFragment::Statement {
219			line: StatementLine(300),
220			column: StatementColumn(75),
221			text: "closure fragment".to_string(),
222		};
223
224		let err = error!(sequence_exhausted(Type::Uint8), get_fragment);
225		let diagnostic = err.diagnostic();
226		let fragment = diagnostic.fragment();
227		assert!(fragment.is_some());
228		assert_eq!(fragment.as_ref().unwrap().line().0, 300);
229	}
230}