sqlstate-inline 0.1.2

Memory efficient const-friendly types for SQLSTATE codes
Documentation
// © 2022 Christoph Grenz <https://grenz-bonn.de>
//
// SPDX-License-Identifier: MPL-2.0

#![cfg_attr(not(feature = "std"), no_std)]

/// Helper macro: maps digits and identifiers to `Char` variants.
macro_rules! _sqlstate {
	(0) => {
		$crate::character::Char::_0
	};
	(1) => {
		$crate::character::Char::_1
	};
	(2) => {
		$crate::character::Char::_2
	};
	(3) => {
		$crate::character::Char::_3
	};
	(4) => {
		$crate::character::Char::_4
	};
	(5) => {
		$crate::character::Char::_5
	};
	(6) => {
		$crate::character::Char::_6
	};
	(7) => {
		$crate::character::Char::_7
	};
	(8) => {
		$crate::character::Char::_8
	};
	(9) => {
		$crate::character::Char::_9
	};
	($x:ident) => {
		$crate::character::Char::$x
	};
}

/// Simplifies creation of `SqlState` and `Class` patterns inside this crate.
///
/// - `sqlstate![0 1 2 3 4]` produces a constant with the same value as `SqlState::from_str("01234")?`
/// - `sqlstate![0 1 2 ..]` generates a pattern that matches `SqlState::from_str("012xx")?`
/// - `sqlstate![0 1 ..]` generates a pattern that matches `SqlState::from_str("01xxx")?` etc.
macro_rules! sqlstate {
	($a:tt $b:tt $c:tt $d:tt $e:tt) => {
		$crate::SqlState {
			code: [
				_sqlstate!($a),
				_sqlstate!($b),
				_sqlstate!($c),
				_sqlstate!($d),
				_sqlstate!($e),
			],
		}
	};
	($a:tt $b:tt $c:tt $d:tt ..) => {
		$crate::SqlState {
			code: [
				_sqlstate!($a),
				_sqlstate!($b),
				_sqlstate!($c),
				_sqlstate!($d),
				..,
			],
		}
	};
	($a:tt $b:tt $c:tt ..) => {
		$crate::SqlState {
			code: [_sqlstate!($a), _sqlstate!($b), _sqlstate!($c), ..],
		}
	};
	($a:tt $b:tt ..) => {
		$crate::SqlState {
			code: [_sqlstate!($a), _sqlstate!($b), ..],
		}
	};
	($a:tt ..) => {
		$crate::SqlState {
			code: [_sqlstate!($a), ..],
		}
	};
	($a:tt $b:tt) => {
		$crate::Class {
			code: [_sqlstate!($a), _sqlstate!($b)],
		}
	};
}

mod category;
mod character;
mod class;
mod error;
mod sqlstate;

pub use category::Category;
pub use class::Class;
pub use error::ParseError;
pub use sqlstate::SqlState;

/// Helper module for import trickery to overlay functions over structs
#[allow(non_snake_case)]
mod _fn {
	/// SQLSTATE constant constructor
	///
	/// Can be used to define constant values for [`SqlState`] from string literals.
	///
	/// Use [`SqlState::from_str()`] for non-literals.
	///
	/// # Panics
	/// Panics if the passed string is not a valid SQLSTATE.
	///
	/// # Examples
	/// ```
	/// # use sqlstate_inline::SqlState;
	/// # fn some_db_query_function<T>(_:T) -> SqlState { SqlState("XRUST") }
	/// const MY_ERROR: SqlState = SqlState("XRUST");
	///
	/// let sqlstate = some_db_query_function(..);
	///
	/// match sqlstate {
	///   MY_ERROR => println!("got my expected error"),
	///   _ => panic!("unexpected condition")
	/// }
	/// ```
	///
	/// An invalid SQLSTATE code in a constant context will cause a compile time panic:
	/// ```compile_fail
	/// # use sqlstate_inline::{SqlState};
	/// const MY_ERROR_CLASS: SqlState = SqlState("!RUST"); // error: evaluation of constant value failed
	/// ```
	/// but an invalid SQLSTATE code in a non-constant context may only panic at runtime:
	/// ```should_panic
	/// # use sqlstate_inline::{SqlState};
	/// let some_class = SqlState("!RUST"); // panics
	/// ```
	/// [`SqlState`]: `struct@super::SqlState`
	/// [`SqlState::from_str()`]: `super::SqlState::from_str()`
	#[inline]
	pub const fn SqlState(value: &'static str) -> super::SqlState {
		match super::SqlState::from_str(value) {
			Ok(result) => result,
			Err(_) => panic!("{}", "invalid SQLSTATE string"),
		}
	}

	/// Class code constant constructor
	///
	/// Can be used to define constant values for [`Class`] from string literals.
	///
	/// Use [`Class::from_str()`] for non-literals.
	///
	/// # Panics
	/// Panics if the passed string is not a valid class code.
	///
	/// # Examples
	/// ```
	/// # use sqlstate_inline::{SqlState, Class};
	/// # fn some_db_query_function<T>(_:T) -> SqlState { SqlState("XRUST") }
	/// const MY_ERROR_CLASS: Class = Class("XR");
	///
	/// let sqlstate = some_db_query_function(..);
	///
	/// match sqlstate.class() {
	///   MY_ERROR_CLASS => println!("got an error in my expected class"),
	///   _ => panic!("unexpected condition")
	/// }
	/// ```
	///
	/// An invalid class code in a constant context will cause a compile time panic:
	/// ```compile_fail
	/// # use sqlstate_inline::{Class};
	/// const MY_ERROR_CLASS: Class = Class("!R"); // error: evaluation of constant value failed
	/// ```
	/// but an invalid class code in a non-constant context may only panic at runtime:
	/// ```should_panic
	/// # use sqlstate_inline::{Class};
	/// let some_class = Class("!R"); // panics
	/// ```
	/// [`Class`]: `struct@super::Class`
	/// [`Class::from_str()`]: `super::Class::from_str()`
	#[inline]
	pub const fn Class(value: &'static str) -> super::Class {
		match super::Class::from_str(value) {
			Ok(result) => result,
			Err(_) => panic!("{}", "invalid SQLSTATE class string"),
		}
	}
}
pub use _fn::*;