use std::{
error::Error as ErrorTrait,
fmt,
num::ParseIntError,
panic,
string::FromUtf8Error,
};
use tokio::{io, task::JoinError};
#[derive(Debug, Clone)]
pub struct AlreadyRunning;
impl fmt::Display for AlreadyRunning {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.pad("there already is an instance of terminal services running")
}
}
impl ErrorTrait for AlreadyRunning {}
#[derive(Debug, Clone)]
pub struct ServicesOff;
impl fmt::Display for ServicesOff {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.pad("terminal event listener and/or screen render disconnected")
}
}
impl ErrorTrait for ServicesOff {}
#[cfg(feature = "clipboard")]
#[derive(Debug)]
pub struct ClipboardError {
inner: anyhow::Error,
}
#[cfg(feature = "clipboard")]
impl ClipboardError {
pub(crate) fn new<E>(inner: E) -> Self
where
E: fmt::Display,
{
Self { inner: anyhow::anyhow!("{}", inner) }
}
}
#[cfg(feature = "clipboard")]
impl fmt::Display for ClipboardError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Clipboard error: {}", self.inner)
}
}
#[derive(Debug)]
pub struct TaskJoinError {
inner: JoinError,
}
impl TaskJoinError {
pub(crate) fn new(inner: JoinError) -> Self {
match inner.try_into_panic() {
Ok(payload) => panic::resume_unwind(payload),
Err(inner) => Self { inner },
}
}
}
impl fmt::Display for TaskJoinError {
fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.inner, fmtr)
}
}
impl ErrorTrait for TaskJoinError {
fn source(&self) -> Option<&(dyn ErrorTrait + 'static)> {
Some(&self.inner)
}
}
#[cfg(feature = "clipboard")]
impl ErrorTrait for ClipboardError {}
#[derive(Debug)]
#[non_exhaustive]
pub enum ErrorKind {
AlreadyRunning(AlreadyRunning),
ServicesOff(ServicesOff),
IO(io::Error),
Fmt(fmt::Error),
ParseInt(ParseIntError),
Utf8(FromUtf8Error),
TaskJoin(TaskJoinError),
#[cfg(feature = "clipboard")]
Clipboard(ClipboardError),
Custom(Box<dyn ErrorTrait + Send + Sync>),
}
impl ErrorKind {
pub fn as_dyn(&self) -> &(dyn ErrorTrait + 'static + Send + Sync) {
match self {
ErrorKind::AlreadyRunning(error) => error,
ErrorKind::ServicesOff(error) => error,
ErrorKind::IO(error) => error,
ErrorKind::Fmt(error) => error,
ErrorKind::ParseInt(error) => error,
ErrorKind::Utf8(error) => error,
ErrorKind::TaskJoin(error) => error,
#[cfg(feature = "clipboard")]
ErrorKind::Clipboard(error) => error,
ErrorKind::Custom(error) => &**error,
}
}
}
impl From<AlreadyRunning> for ErrorKind {
fn from(error: AlreadyRunning) -> Self {
ErrorKind::AlreadyRunning(error)
}
}
impl From<ServicesOff> for ErrorKind {
fn from(error: ServicesOff) -> Self {
ErrorKind::ServicesOff(error)
}
}
impl From<io::Error> for ErrorKind {
fn from(error: io::Error) -> Self {
ErrorKind::IO(error)
}
}
impl From<ParseIntError> for ErrorKind {
fn from(error: ParseIntError) -> Self {
ErrorKind::ParseInt(error)
}
}
impl From<FromUtf8Error> for ErrorKind {
fn from(error: FromUtf8Error) -> Self {
ErrorKind::Utf8(error)
}
}
impl From<TaskJoinError> for ErrorKind {
fn from(error: TaskJoinError) -> Self {
ErrorKind::TaskJoin(error)
}
}
impl From<fmt::Error> for ErrorKind {
fn from(error: fmt::Error) -> Self {
ErrorKind::Fmt(error)
}
}
#[cfg(feature = "clipboard")]
impl From<ClipboardError> for ErrorKind {
fn from(error: ClipboardError) -> Self {
ErrorKind::Clipboard(error)
}
}
impl From<Box<dyn ErrorTrait + Send + Sync>> for ErrorKind {
fn from(error: Box<dyn ErrorTrait + Send + Sync>) -> Self {
ErrorKind::Custom(error)
}
}
#[derive(Debug)]
pub struct Error {
kind: Box<ErrorKind>,
}
impl Error {
pub fn new(kind: ErrorKind) -> Self {
Self { kind: Box::new(kind) }
}
pub fn as_dyn(&self) -> &(dyn ErrorTrait + 'static + Send + Sync) {
self.kind.as_dyn()
}
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.as_dyn())
}
}
impl ErrorTrait for Error {
fn source(&self) -> Option<&(dyn ErrorTrait + 'static)> {
Some(self.as_dyn())
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Self::new(kind)
}
}
impl From<AlreadyRunning> for Error {
fn from(error: AlreadyRunning) -> Self {
Self::new(ErrorKind::from(error))
}
}
impl From<ServicesOff> for Error {
fn from(error: ServicesOff) -> Self {
Self::new(ErrorKind::from(error))
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Self::new(ErrorKind::from(error))
}
}
impl From<ParseIntError> for Error {
fn from(error: ParseIntError) -> Self {
Self::new(ErrorKind::from(error))
}
}
impl From<FromUtf8Error> for Error {
fn from(error: FromUtf8Error) -> Self {
Self::new(ErrorKind::from(error))
}
}
impl From<fmt::Error> for Error {
fn from(error: fmt::Error) -> Self {
Self::new(ErrorKind::from(error))
}
}
impl From<TaskJoinError> for Error {
fn from(error: TaskJoinError) -> Self {
Self::new(ErrorKind::from(error))
}
}
#[cfg(feature = "clipboard")]
impl From<ClipboardError> for Error {
fn from(error: ClipboardError) -> Self {
Self::new(ErrorKind::from(error))
}
}
impl From<Box<dyn ErrorTrait + Send + Sync>> for Error {
fn from(error: Box<dyn ErrorTrait + Send + Sync>) -> Self {
Self::new(ErrorKind::from(error))
}
}