use std::{fmt, result};

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Error {
  RusbError(rusb::Error),
  Other(String),
}

impl Error {
  pub fn new<S: Into<String>>(msg: S) -> Self {
    Error::Other(msg.into())
  }
}

impl fmt::Display for Error {
  fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
    match self {
      Error::RusbError(err) => write!(f, "USB Error: {}", err),
      Error::Other(err) => write!(f, "{}", err),
    }
  }
}

impl std::error::Error for Error {}

impl From<rusb::Error> for Error {
  fn from(err: rusb::Error) -> Self {
    Error::RusbError(err)
  }
}

impl From<ctrlc::Error> for Error {
  fn from(err: ctrlc::Error) -> Self {
    Error::Other(err.to_string())
  }
}

impl From<std::str::Utf8Error> for Error {
  fn from(err: std::str::Utf8Error) -> Self {
    Error::Other(err.to_string())
  }
}
