sqlstate_inline/
lib.rs

1// © 2022 Christoph Grenz <https://grenz-bonn.de>
2//
3// SPDX-License-Identifier: MPL-2.0
4
5#![cfg_attr(not(feature = "std"), no_std)]
6
7/// Helper macro: maps digits and identifiers to `Char` variants.
8macro_rules! _sqlstate {
9	(0) => {
10		$crate::character::Char::_0
11	};
12	(1) => {
13		$crate::character::Char::_1
14	};
15	(2) => {
16		$crate::character::Char::_2
17	};
18	(3) => {
19		$crate::character::Char::_3
20	};
21	(4) => {
22		$crate::character::Char::_4
23	};
24	(5) => {
25		$crate::character::Char::_5
26	};
27	(6) => {
28		$crate::character::Char::_6
29	};
30	(7) => {
31		$crate::character::Char::_7
32	};
33	(8) => {
34		$crate::character::Char::_8
35	};
36	(9) => {
37		$crate::character::Char::_9
38	};
39	($x:ident) => {
40		$crate::character::Char::$x
41	};
42}
43
44/// Simplifies creation of `SqlState` and `Class` patterns inside this crate.
45///
46/// - `sqlstate![0 1 2 3 4]` produces a constant with the same value as `SqlState::from_str("01234")?`
47/// - `sqlstate![0 1 2 ..]` generates a pattern that matches `SqlState::from_str("012xx")?`
48/// - `sqlstate![0 1 ..]` generates a pattern that matches `SqlState::from_str("01xxx")?` etc.
49macro_rules! sqlstate {
50	($a:tt $b:tt $c:tt $d:tt $e:tt) => {
51		$crate::SqlState {
52			code: [
53				_sqlstate!($a),
54				_sqlstate!($b),
55				_sqlstate!($c),
56				_sqlstate!($d),
57				_sqlstate!($e),
58			],
59		}
60	};
61	($a:tt $b:tt $c:tt $d:tt ..) => {
62		$crate::SqlState {
63			code: [
64				_sqlstate!($a),
65				_sqlstate!($b),
66				_sqlstate!($c),
67				_sqlstate!($d),
68				..,
69			],
70		}
71	};
72	($a:tt $b:tt $c:tt ..) => {
73		$crate::SqlState {
74			code: [_sqlstate!($a), _sqlstate!($b), _sqlstate!($c), ..],
75		}
76	};
77	($a:tt $b:tt ..) => {
78		$crate::SqlState {
79			code: [_sqlstate!($a), _sqlstate!($b), ..],
80		}
81	};
82	($a:tt ..) => {
83		$crate::SqlState {
84			code: [_sqlstate!($a), ..],
85		}
86	};
87	($a:tt $b:tt) => {
88		$crate::Class {
89			code: [_sqlstate!($a), _sqlstate!($b)],
90		}
91	};
92}
93
94mod category;
95mod character;
96mod class;
97mod error;
98mod sqlstate;
99
100pub use category::Category;
101pub use class::Class;
102pub use error::ParseError;
103pub use sqlstate::SqlState;
104
105/// Helper module for import trickery to overlay functions over structs
106#[allow(non_snake_case)]
107mod _fn {
108	/// SQLSTATE constant constructor
109	///
110	/// Can be used to define constant values for [`SqlState`] from string literals.
111	///
112	/// Use [`SqlState::from_str()`] for non-literals.
113	///
114	/// # Panics
115	/// Panics if the passed string is not a valid SQLSTATE.
116	///
117	/// # Examples
118	/// ```
119	/// # use sqlstate_inline::SqlState;
120	/// # fn some_db_query_function<T>(_:T) -> SqlState { SqlState("XRUST") }
121	/// const MY_ERROR: SqlState = SqlState("XRUST");
122	///
123	/// let sqlstate = some_db_query_function(..);
124	///
125	/// match sqlstate {
126	///   MY_ERROR => println!("got my expected error"),
127	///   _ => panic!("unexpected condition")
128	/// }
129	/// ```
130	///
131	/// An invalid SQLSTATE code in a constant context will cause a compile time panic:
132	/// ```compile_fail
133	/// # use sqlstate_inline::{SqlState};
134	/// const MY_ERROR_CLASS: SqlState = SqlState("!RUST"); // error: evaluation of constant value failed
135	/// ```
136	/// but an invalid SQLSTATE code in a non-constant context may only panic at runtime:
137	/// ```should_panic
138	/// # use sqlstate_inline::{SqlState};
139	/// let some_class = SqlState("!RUST"); // panics
140	/// ```
141	/// [`SqlState`]: `struct@super::SqlState`
142	/// [`SqlState::from_str()`]: `super::SqlState::from_str()`
143	#[inline]
144	pub const fn SqlState(value: &'static str) -> super::SqlState {
145		match super::SqlState::from_str(value) {
146			Ok(result) => result,
147			Err(_) => panic!("{}", "invalid SQLSTATE string"),
148		}
149	}
150
151	/// Class code constant constructor
152	///
153	/// Can be used to define constant values for [`Class`] from string literals.
154	///
155	/// Use [`Class::from_str()`] for non-literals.
156	///
157	/// # Panics
158	/// Panics if the passed string is not a valid class code.
159	///
160	/// # Examples
161	/// ```
162	/// # use sqlstate_inline::{SqlState, Class};
163	/// # fn some_db_query_function<T>(_:T) -> SqlState { SqlState("XRUST") }
164	/// const MY_ERROR_CLASS: Class = Class("XR");
165	///
166	/// let sqlstate = some_db_query_function(..);
167	///
168	/// match sqlstate.class() {
169	///   MY_ERROR_CLASS => println!("got an error in my expected class"),
170	///   _ => panic!("unexpected condition")
171	/// }
172	/// ```
173	///
174	/// An invalid class code in a constant context will cause a compile time panic:
175	/// ```compile_fail
176	/// # use sqlstate_inline::{Class};
177	/// const MY_ERROR_CLASS: Class = Class("!R"); // error: evaluation of constant value failed
178	/// ```
179	/// but an invalid class code in a non-constant context may only panic at runtime:
180	/// ```should_panic
181	/// # use sqlstate_inline::{Class};
182	/// let some_class = Class("!R"); // panics
183	/// ```
184	/// [`Class`]: `struct@super::Class`
185	/// [`Class::from_str()`]: `super::Class::from_str()`
186	#[inline]
187	pub const fn Class(value: &'static str) -> super::Class {
188		match super::Class::from_str(value) {
189			Ok(result) => result,
190			Err(_) => panic!("{}", "invalid SQLSTATE class string"),
191		}
192	}
193}
194pub use _fn::*;