#![cfg_attr(nightly, feature(backtrace))]
#![cfg_attr(nightly, feature(no_coverage))]
use std::{
borrow::Cow,
fmt::{self, Debug, Display},
ops::{Deref, DerefMut},
str::FromStr,
};
#[cfg(nightly)]
use std::backtrace::Backtrace;
use mdsn::DsnError;
macro_rules! _impl_fmt {
($fmt:ident) => {
impl fmt::$fmt for Code {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::$fmt::fmt(&self.0, f)
}
}
};
}
_impl_fmt!(LowerHex);
_impl_fmt!(UpperHex);
#[derive(Clone, Copy, Eq, PartialEq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Code(i32);
impl Code {
pub const COLUMN_EXISTS: Code = Code(0x036B);
pub const COLUMN_NOT_EXIST: Code = Code(0x036C);
pub const TAG_ALREADY_EXIST: Code = Code(0x0369);
pub const TAG_NOT_EXIST: Code = Code(0x036A);
pub const MODIFIED_ALREADY: Code = Code(0x264B);
pub const INVALID_COLUMN_NAME: Code = Code(0x2602);
pub const TABLE_NOT_EXIST: Code = Code(0x2603);
pub const STABLE_NOT_EXIST: Code = Code(0x0362);
pub const INVALID_ROW_BYTES: Code = Code(0x036F);
pub const DUPLICATED_COLUMN_NAMES: Code = Code(0x263C);
pub const NO_COLUMN_CAN_BE_DROPPED: Code = Code(0x2651);
}
impl Display for Code {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{:#06X}", *self))
}
}
impl Debug for Code {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!(
"Code([{:#06X}] {})",
self.0,
self.as_error_str()
))
}
}
macro_rules! _impl_from {
($($from:ty) *) => {
$(
impl From<$from> for Code {
#[inline]
fn from(c: $from) -> Self {
Self(c as i32 & 0xFFFF)
}
}
impl From<Code> for $from {
#[inline]
fn from(c: Code) -> Self {
c.0 as _
}
}
)*
};
}
_impl_from!(i8 u8 i16 i32 u16 u32 i64 u64);
impl Deref for Code {
type Target = i32;
fn deref(&self) -> &i32 {
&self.0
}
}
impl DerefMut for Code {
fn deref_mut(&mut self) -> &mut i32 {
&mut self.0
}
}
impl Code {
pub const fn new(code: i32) -> Self {
Code(code)
}
}
impl PartialEq<usize> for Code {
fn eq(&self, other: &usize) -> bool {
self.0 == *other as i32
}
}
impl PartialEq<isize> for Code {
fn eq(&self, other: &isize) -> bool {
self.0 == *other as i32
}
}
impl PartialEq<i32> for Code {
fn eq(&self, other: &i32) -> bool {
self.0 == *other
}
}
#[allow(non_upper_case_globals, non_snake_case)]
#[cfg_attr(feature = "no_coverage", no_coverage)]
mod code {
include!(concat!(env!("OUT_DIR"), "/code.rs"));
}
#[derive(Debug, thiserror::Error)]
pub struct Error {
code: Code,
err: Cow<'static, str>,
#[cfg(nightly)]
backtrace: Backtrace,
}
impl From<DsnError> for Error {
fn from(dsn: DsnError) -> Self {
Self::new(Code::Failed, dsn.to_string())
}
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
#[inline]
pub fn new(code: impl Into<Code>, err: impl Into<Cow<'static, str>>) -> Self {
Self {
code: code.into(),
err: err.into(),
#[cfg(nightly)]
#[cfg_attr(nightly, no_coverage)]
backtrace: Backtrace::capture(),
}
}
#[inline]
pub fn errno(&self) -> Code {
self.code
}
#[inline]
pub const fn code(&self) -> Code {
self.code
}
#[inline]
pub fn message(&self) -> &str {
&self.err
}
#[inline]
pub fn from_code(code: impl Into<Code>) -> Self {
Self::new(code, "")
}
#[inline]
pub fn from_string(err: impl Into<Cow<'static, str>>) -> Self {
Self::new(Code::Failed, err)
}
#[inline]
pub fn from_any(err: impl Display) -> Self {
Self::new(Code::Failed, err.to_string())
}
}
impl FromStr for Error {
type Err = ();
#[inline]
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Ok(Self::from_string(s.to_string()))
}
}
impl Display for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.code == Code::Failed {
write!(f, "{}", self.err)
} else {
write!(f, "[{:#06X}] {}", self.code, self.err)
}
}
}
#[cfg(feature = "serde")]
impl serde::de::Error for Error {
#[inline]
fn custom<T: fmt::Display>(msg: T) -> Error {
Error::from_string(format!("{}", msg))
}
}
#[test]
fn test_code() {
let c: i32 = Code::new(0).into();
assert_eq!(c, 0);
let c = Code::from(0).to_string();
assert_eq!(c, "0x0000");
dbg!(Code::from(0x200));
let c: i8 = Code::new(0).into();
let mut c: Code = c.into();
let _: &i32 = c.deref();
let _: &mut i32 = c.deref_mut();
}
#[test]
fn test_display() {
let err = Error::new(Code::Success, "Success");
assert_eq!(format!("{err}"), "[0x0000] Success");
let err = Error::new(Code::Failed, "failed");
assert_eq!(format!("{err}"), "failed");
}
#[test]
fn test_error() {
let err = Error::new(Code::Success, "success");
assert_eq!(err.code(), err.errno());
assert_eq!(err.message(), "success");
let _ = Error::from_code(1);
assert_eq!(Error::from_any("any").to_string(), "any");
assert_eq!(Error::from_string("any").to_string(), "any");
let _ = Error::from(DsnError::InvalidDriver("".to_string()));
}
#[cfg(feature = "serde")]
#[test]
fn test_serde_error() {
use serde::de::Error as DeError;
let _ = Error::custom("");
}