userror/
lib.rs

1//! Some basic functions and macros for printing user-facing errors in command-line programs.
2//!
3//! # Installation
4//!
5//! Simply mark userror as a dependency in your Cargo.toml
6//!
7//! ```toml
8//! [dependencies]
9//! userror = "0.1.0"
10//! ```
11//!
12//! By default userror prints coloured messages with ansi_term, if you do not want this use
13//! `default-features = false`
14//!
15//! ```toml
16//! [dependencies]
17//! userror = { version = "0.1.0", default-features = false }
18//! ```
19
20#[cfg(feature = "colour")]
21extern crate ansi_term;
22
23#[cfg(feature = "colour")]
24use ansi_term::Colour;
25
26#[cfg(not(feature = "colour"))]
27enum Colour {
28    Purple,
29    Blue,
30    Yellow,
31    Red,
32}
33
34#[cfg(not(feature = "colour"))]
35impl Colour {
36    fn paint<'l>(&self, level: &'l str) -> &'l str {
37        level
38    }
39}
40
41
42use std::io::{self, Write};
43
44/// Prepend file and line info into a given message.
45///
46/// This is useful for internal errors to avoid messy uses of `file!` and `line!`.
47///
48/// The first argument to this macro must always be a string literal. If a single argument is
49/// given then a `&'static str` will be returned. If multiple arguments are given the the first
50/// argument is used as a format string for `format!`.
51#[macro_export]
52macro_rules! flm {
53    () => (concat!(file!(), ":", line!()));
54
55    ($message:expr) => (concat!(file!(), ":", line!(), ": ", $message));
56
57    ($format:expr, $( $val:expr ),+) => (
58        format!(concat!(file!(), ":", line!(), ": ", $format), $( $val ),+)
59    );
60}
61
62/// Prepend file and line info into a call to `.expect()`.
63#[macro_export]
64macro_rules! expect {
65    ($value:expr) => ($value.expect(flm!()));
66
67    ($value:expr, $message:expr) => ($value.expect(flm!($message)));
68}
69
70/// Display an internal error message with file and line info.
71///
72/// Internal errors are bugs or failed invariants in your program, hence file and line info are
73/// useful for debugging.
74#[macro_export]
75macro_rules! internal {
76    ($message:expr) => ($crate::internal(flm!($message)));
77
78    ($format:expr, $( $val:expr ),+) => ($crate::internal(&flm!($format, $( $val ),+)));
79}
80
81fn print(colour: Colour, level: &str, message: &str) -> io::Result<()> {
82    let program = try!(std::env::current_exe());
83    let program = program.file_name().and_then(|n| n.to_str());
84    match program {
85        Some(name) => writeln!(
86            io::stderr(),
87            "{}:{}: {}",
88            Colour::Blue.paint(name),
89            colour.paint(level),
90            message,
91        ),
92        None => writeln!(io::stderr(), "{}: {}", colour.paint(level), message),
93    }
94}
95
96/// Print an internal error message.
97///
98/// Internal errors are bugs or failed invariants in your program. They are not necessarily fatal.
99pub fn internal(message: &str) -> io::Result<()> {
100    print(Colour::Red, "internal", message)
101}
102
103/// Print a fatal error message and panic.
104///
105/// Fatal errors are errors which can not be recovered from, such as failing to receive user input.
106pub fn fatal(message: &str) -> ! {
107    print(Colour::Red, "fatal", message).expect("failed to write error message");
108    panic!("fatal error occurred");
109}
110
111/// Print an error message.
112///
113/// Errors are recoverable but prevent the program from working properly or in it's entirety, such
114/// as failing to open an output file and instead printing results to screen.
115pub fn error(message: &str) -> io::Result<()> {
116    print(Colour::Red, "error", message)
117}
118
119/// Print a warning message.
120///
121/// Warnings lead to sub-optimal, but not strictly incorrect, behaviour. An example would be
122/// failing to load a custom stylesheet and instead using a default one.
123pub fn warn(message: &str) -> io::Result<()> {
124    print(Colour::Yellow, "warning", message)
125}
126
127/// Print some non-erroneous information.
128pub fn info(message: &str) -> io::Result<()> {
129    print(Colour::Purple, "info", message)
130}