use core::fmt;
use core::ops::Deref;
use core::str::FromStr;
#[cfg(feature = "std")]
use std::io;
use crate::category::Category;
use crate::character::Char;
use crate::class::Class;
use crate::error::ParseError;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SqlState {
code: [Char; 5],
}
impl SqlState {
#[inline]
pub const fn from_str(value: &str) -> Result<Self, ParseError> {
Self::from_bytes(value.as_bytes())
}
#[inline]
pub const fn from_str_lossy(value: &str) -> Self {
Self::from_bytes_lossy(value.as_bytes())
}
#[inline]
pub const fn from_bytes(value: &[u8]) -> Result<Self, ParseError> {
match Char::new_array(value) {
Ok(code) => Ok(Self { code }),
Err(e) => Err(e),
}
}
#[inline]
pub const fn from_bytes_lossy(value: &[u8]) -> Self {
if value.is_empty() {
Self::UNKNOWN
} else {
Self {
code: Char::new_array_lossy(value, Char::X),
}
}
}
pub const fn from_byte_array(value: [u8; 5]) -> Result<Self, ParseError> {
match Char::new_array(&value) {
Ok(code) => Ok(Self { code }),
Err(e) => Err(e),
}
}
#[inline]
pub const fn category(&self) -> Category {
match self {
sqlstate![0 0 ..] => Category::Success,
sqlstate![0 1 ..] => Category::Warning,
sqlstate![0 2 ..] => Category::NoData,
_ => Category::Exception,
}
}
#[inline]
pub const fn class(&self) -> Class {
match self.code {
[a, b, _, _, _] => Class { code: [a, b] },
}
}
#[inline]
pub const fn is_implementation_specific(&self) -> bool {
!matches!(
self.code[0],
Char::_0
| Char::_1 | Char::_2
| Char::_3 | Char::_4
| Char::A | Char::B
| Char::C | Char::D
| Char::E | Char::F
| Char::G | Char::H
) || !matches!(
self.code[2],
Char::_0
| Char::_1 | Char::_2
| Char::_3 | Char::_4
| Char::A | Char::B
| Char::C | Char::D
| Char::E | Char::F
| Char::G | Char::H
)
}
#[inline]
pub const fn has_subclass(&self) -> bool {
!matches!(self.code, [_, _, Char::_0, Char::_0, Char::_0])
}
pub const UNKNOWN: Self = sqlstate![9 9 9 9 9];
}
impl fmt::Debug for SqlState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_tuple("SqlState").field(&&**self).finish()
}
}
impl fmt::Display for SqlState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str(self)
}
}
impl AsRef<str> for SqlState {
#[inline]
fn as_ref(&self) -> &str {
self
}
}
impl AsRef<[u8]> for SqlState {
#[inline]
fn as_ref(&self) -> &[u8] {
Char::array_as_bytes(&self.code)
}
}
impl AsRef<[u8; 5]> for SqlState {
#[inline]
fn as_ref(&self) -> &[u8; 5] {
Char::array_as_bytes(&self.code)
}
}
impl From<SqlState> for [u8; 5] {
#[inline]
fn from(sqlstate: SqlState) -> Self {
sqlstate.code.map(Char::as_byte)
}
}
impl Deref for SqlState {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
Char::array_as_str(&self.code)
}
}
impl PartialEq<str> for SqlState {
fn eq(&self, other: &str) -> bool {
&**self == other
}
}
impl PartialEq<[u8]> for SqlState {
fn eq(&self, other: &[u8]) -> bool {
AsRef::<[u8]>::as_ref(self) == other
}
}
#[cfg(feature = "std")]
impl From<SqlState> for io::ErrorKind {
fn from(state: SqlState) -> Self {
match state {
sqlstate![0 8 0 0 1] | sqlstate![0 8 0 0 4] => Self::ConnectionRefused,
sqlstate![0 8 0 0 3] => Self::ConnectionAborted,
sqlstate![0 8 ..] => Self::ConnectionReset,
sqlstate![0 A ..] => Self::Unsupported,
sqlstate![2 1 ..] => Self::InvalidInput,
sqlstate![2 2 ..] => Self::InvalidData,
sqlstate![2 3 5 0 5] => Self::AlreadyExists,
sqlstate![2 3 ..] => Self::PermissionDenied,
sqlstate![2 5 P 0 3] => Self::TimedOut,
sqlstate![2 6 ..] => Self::InvalidData,
sqlstate![2 8 ..] => Self::PermissionDenied,
sqlstate![4 0 0 0 2] => Self::PermissionDenied,
sqlstate![4 2 5 ..] => Self::PermissionDenied,
sqlstate![4 2 S 0 1] => Self::AlreadyExists,
sqlstate![4 2 S 0 2] | sqlstate![4 2 S 1 2] => Self::NotFound,
sqlstate![4 2 ..] => Self::InvalidInput,
sqlstate![4 4 ..] => Self::PermissionDenied,
sqlstate![5 3 2 0 0] => Self::OutOfMemory,
sqlstate![5 3 3 0 0] => Self::ConnectionRefused,
sqlstate![5 4 ..] => Self::InvalidInput,
sqlstate![5 7 0 1 4] => Self::Interrupted,
sqlstate![5 7 P 0 1] => Self::ConnectionReset,
sqlstate![5 7 P 0 2] => Self::ConnectionReset,
sqlstate![5 7 P 0 3] => Self::ConnectionRefused,
sqlstate![5 7 P 0 5] => Self::ConnectionAborted,
sqlstate![7 0 1 0 0] => Self::Interrupted,
sqlstate![H V 0 0 1] => Self::OutOfMemory,
sqlstate![H V 0 0 N] => Self::BrokenPipe,
sqlstate![H Y 0 0 1] => Self::OutOfMemory,
sqlstate![H Y 0 0 8] => Self::TimedOut,
sqlstate![X X 0 0 1] | sqlstate![X X 0 0 2] => Self::UnexpectedEof,
_ => Self::Other,
}
}
}
impl FromStr for SqlState {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_bytes(s.as_bytes())
}
}
impl TryFrom<&[u8]> for SqlState {
type Error = ParseError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
Self::from_bytes(bytes)
}
}
impl TryFrom<[u8; 5]> for SqlState {
type Error = ParseError;
fn try_from(bytes: [u8; 5]) -> Result<Self, Self::Error> {
Self::from_byte_array(bytes)
}
}
impl TryFrom<&str> for SqlState {
type Error = ParseError;
fn try_from(string: &str) -> Result<Self, Self::Error> {
Self::from_str(string)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for SqlState {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for SqlState {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer
.deserialize_str(crate::character::de::ArrayVisitor::new())
.map(|arr| Self { code: arr })
}
}
const _: () = assert!(core::mem::size_of::<SqlState>() == 5);
const _: () = assert!(core::mem::size_of::<Option<Option<SqlState>>>() == 5);