use std::fmt;
use crate::layout::InvalidKeySize;
use crate::utils::InvalidColor;
#[derive(Debug)]
pub struct Error {
inner: Box<ErrorImpl>,
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub(crate) enum ErrorImpl {
JsonParseError(serde_json::Error),
TomlParseError(toml::de::Error),
FontParseError(ttf_parser::FaceParsingError),
InvalidKeySize(InvalidKeySize),
InvalidColor(InvalidColor),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self.inner {
ErrorImpl::JsonParseError(error) => write!(f, "error parsing JSON: {error}"),
ErrorImpl::TomlParseError(error) => write!(f, "error parsing TOML: {error}"),
ErrorImpl::FontParseError(error) => write!(f, "error parsing font: {error}"),
ErrorImpl::InvalidKeySize(error) => write!(f, "error parsing KLE layout: {error}"),
ErrorImpl::InvalidColor(error) => write!(f, "error parsing color: {error}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &*self.inner {
ErrorImpl::JsonParseError(error) => Some(error),
ErrorImpl::TomlParseError(error) => Some(error),
ErrorImpl::FontParseError(error) => Some(error),
ErrorImpl::InvalidKeySize(_) | ErrorImpl::InvalidColor(_) => None,
}
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Self {
Self {
inner: Box::new(ErrorImpl::JsonParseError(error)),
}
}
}
impl From<toml::de::Error> for Error {
fn from(error: toml::de::Error) -> Self {
Self {
inner: Box::new(ErrorImpl::TomlParseError(error)),
}
}
}
impl From<ttf_parser::FaceParsingError> for Error {
fn from(error: ttf_parser::FaceParsingError) -> Self {
Self {
inner: Box::new(ErrorImpl::FontParseError(error)),
}
}
}
impl From<InvalidKeySize> for Error {
fn from(error: InvalidKeySize) -> Self {
Self {
inner: Box::new(ErrorImpl::InvalidKeySize(error)),
}
}
}
impl From<InvalidColor> for Error {
fn from(error: InvalidColor) -> Self {
Self {
inner: Box::new(ErrorImpl::InvalidColor(error)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::layout::KeySize;
use crate::utils::Color;
fn json_parse_error() -> Error {
serde_json::from_str::<serde_json::Value>("invalid")
.unwrap_err()
.into()
}
fn toml_parse_error() -> Error {
toml::from_str::<toml::Value>("invalid").unwrap_err().into()
}
fn font_parse_error() -> Error {
ttf_parser::Face::parse(b"invalid", 0).unwrap_err().into()
}
fn invalid_key_size() -> Error {
KeySize::new(1., 1., 1., 1., 1., 1.).unwrap_err().into()
}
fn invalid_color() -> Error {
Color::from_hex("invalid").unwrap_err().into()
}
#[test]
fn test_display_error() {
let config = vec![
(json_parse_error(), "error parsing JSON: expected value at line 1 column 1"),
(toml_parse_error(), r#"error parsing TOML: TOML parse error at line 1, column 8
|
1 | invalid
| ^
expected `.`, `=`
"#),
(font_parse_error(), "error parsing font: unknown magic"),
(invalid_key_size(), "error parsing KLE layout: Unsupported non-standard key size (w: 1.00, h: 1.00, x2: 1.00, y2: 1.00, w2: 1.00, h2: 1.00) Note ISO enter and stepped caps are supported as special cases"),
(invalid_color(), "error parsing color: invalid hex code invalid"),
];
for (err, fmt) in config {
assert_eq!(format!("{err}"), fmt);
}
}
#[test]
fn test_error_source() {
use std::error::Error;
let config = vec![
(json_parse_error(), true),
(toml_parse_error(), true),
(font_parse_error(), true),
(invalid_key_size(), false),
(invalid_color(), false),
];
for (err, has_source) in config {
assert_eq!(err.source().is_some(), has_source);
}
}
}