//! A set of error types for cassiopeia use crate::cass::{Date, Time}; use std::fmt::{self, Display, Formatter}; use std::{error::Error, io}; /// User errors that can occur when using cassiopeia /// /// None of these errors are the fault of the program, but rather /// fault of the user for giving invalid commands. They must never /// make the program crash, but instead need to print human friendly /// error messages. #[derive(Debug)] pub enum UserError { /// Trying to start a session when one exists ActiveSessionExists(Time), /// Trying to stop a session when none exists NoActiveSession(Time), /// Trying to create a second invoice on the same day SameDayInvoice(Date), /// No work was done since the last invoice NoWorkInvoice(Date), } impl Display for UserError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!( f, "{}", match self { Self::ActiveSessionExists(t) => format!("Session since '{}' in progress", t.to_string()), Self::NoActiveSession(t) => format!("No session before '{}'", t.to_string()), Self::SameDayInvoice(d) => format!("More than one invoice on '{}'", d.to_string()), Self::NoWorkInvoice(d) => format!("No work done before '{}'", d.to_string()), } ) } } impl Error for UserError {} pub type UserResult = Result; /// Errors that occur when parsing a file /// /// These errors can pre-maturely terminate the run of the program, /// but must print a detailed error about what is wrong. Also, /// because they are technically a superset of /// [`UserError`](self::UserError), one of the variants is an embedded /// user error. #[derive(Debug)] pub enum ParseError { /// An embedded user error /// /// This error means that the structure of the parsed file is /// wrong, with an invalid sequence of events expressed User(UserError), /// The requested file did not exist NoSuchFile, /// The file could not be read BadPermissions, /// The file could not be written to FileNotWritable, /// Other file related errors FileUnknown(String), /// An invalid keyword was found BadKeyword { line: usize, tokn: String }, /// A bad timestamp was found BadTimestamp { line: usize, tokn: String }, /// A bad date was found BadDate { line: usize, tokn: String }, /// An unexpected sequence was found Unexpected { line: usize, tokn: String }, /// An unknown parse error occured Unknown, } impl Display for ParseError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!( f, "{}", match self { Self::User(err) => format!("User error: {}", err), Self::NoSuchFile => "The file does not exist".into(), Self::BadPermissions => "Insufficient permissions to read the file".into(), Self::FileNotWritable => "Insufficient permissions to write the file".into(), Self::FileUnknown(file) => format!("System I/O error: {}", file), Self::BadKeyword { line, tokn } => format!("Invalid keyword '{}' on line {}", tokn, line), Self::BadTimestamp { line, tokn } => format!("Invalid timestamp '{}' on line {}", tokn, line), Self::BadDate { line, tokn } => format!("Invalid date '{}' on line {}", tokn, line), Self::Unexpected { line, tokn } => format!("Unexpected token '{}' on line {}", tokn, line), Self::Unknown => "An unknown error occured".into(), } ) } } impl Error for ParseError {} pub type ParseResult = Result; impl From for ParseError { fn from(user: UserError) -> Self { ParseError::User(user) } } impl From for ParseError { fn from(e: io::Error) -> Self { use io::ErrorKind::*; match e.kind() { NotFound => Self::NoSuchFile, PermissionDenied => Self::BadPermissions, _ => Self::FileUnknown(format!("{}", e)), } } }