use std::backtrace::{Backtrace, BacktraceStatus};
use std::panic::Location;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum WtErrorKind {
Incomplete,
BufferTooShort,
InvalidInput,
CapsuleDecode,
InvalidStreamId,
StreamStateError,
FlowControlError,
SessionStateError,
SessionClosed,
}
impl std::fmt::Display for WtErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Incomplete => write!(f, "Incomplete"),
Self::BufferTooShort => write!(f, "BufferTooShort"),
Self::InvalidInput => write!(f, "InvalidInput"),
Self::CapsuleDecode => write!(f, "CapsuleDecode"),
Self::InvalidStreamId => write!(f, "InvalidStreamId"),
Self::StreamStateError => write!(f, "StreamStateError"),
Self::FlowControlError => write!(f, "FlowControlError"),
Self::SessionStateError => write!(f, "SessionStateError"),
Self::SessionClosed => write!(f, "SessionClosed"),
}
}
}
pub struct WtError {
pub kind: WtErrorKind,
pub reason: String,
pub location: &'static Location<'static>,
pub backtrace: Backtrace,
}
impl WtError {
#[track_caller]
pub fn new(kind: WtErrorKind) -> Self {
Self::with_reason(kind, String::new())
}
#[track_caller]
pub fn with_reason<T: Into<String>>(kind: WtErrorKind, reason: T) -> Self {
Self {
kind,
reason: reason.into(),
location: Location::caller(),
backtrace: Backtrace::capture(),
}
}
#[track_caller]
pub fn incomplete() -> Self {
Self::new(WtErrorKind::Incomplete)
}
#[track_caller]
pub fn buffer_too_short() -> Self {
Self::new(WtErrorKind::BufferTooShort)
}
#[track_caller]
pub fn invalid_input<T: Into<String>>(reason: T) -> Self {
Self::with_reason(WtErrorKind::InvalidInput, reason)
}
#[track_caller]
pub fn capsule_decode<T: Into<String>>(reason: T) -> Self {
Self::with_reason(WtErrorKind::CapsuleDecode, reason)
}
#[track_caller]
pub fn invalid_stream_id<T: Into<String>>(reason: T) -> Self {
Self::with_reason(WtErrorKind::InvalidStreamId, reason)
}
#[track_caller]
pub fn stream_state_error<T: Into<String>>(reason: T) -> Self {
Self::with_reason(WtErrorKind::StreamStateError, reason)
}
#[track_caller]
pub fn flow_control_error<T: Into<String>>(reason: T) -> Self {
Self::with_reason(WtErrorKind::FlowControlError, reason)
}
#[track_caller]
pub fn session_state_error<T: Into<String>>(reason: T) -> Self {
Self::with_reason(WtErrorKind::SessionStateError, reason)
}
#[track_caller]
pub fn session_closed<T: Into<String>>(reason: T) -> Self {
Self::with_reason(WtErrorKind::SessionClosed, reason)
}
}
impl std::fmt::Debug for WtError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")
}
}
impl std::fmt::Display for WtError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.kind)?;
if !self.reason.is_empty() {
write!(f, ": {}", self.reason)?;
}
write!(f, " (at {}:{})", self.location.file(), self.location.line())?;
if self.backtrace.status() == BacktraceStatus::Captured {
write!(f, "\n\nBacktrace:\n{}", self.backtrace)?;
}
Ok(())
}
}
impl std::error::Error for WtError {}
pub type WtResult<T> = std::result::Result<T, WtError>;