From 4ffee6bacc3579c57687f4029d2fc73213592c39 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 8 Jan 2019 04:13:23 +0000 Subject: Refactor io::Error into custom Error enum --- src/backends/dialog.rs | 32 ++++++++--------------------- src/backends/mod.rs | 2 +- src/lib.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/backends/dialog.rs b/src/backends/dialog.rs index fb0f73f..da17ad1 100644 --- a/src/backends/dialog.rs +++ b/src/backends/dialog.rs @@ -1,11 +1,9 @@ // Copyright (C) 2019 Robin Krahl // SPDX-License-Identifier: MIT -use std::io; -use std::io::Result; use std::process; -use crate::{Choice, Input, Message, Question}; +use crate::{Choice, Error, Input, Message, Question, Result}; /// The `dialog` backend. /// @@ -75,7 +73,7 @@ impl Dialog { command.arg(&self.width); command.args(post_args); - command.output() + command.output().map_err(Error::IoError) } } @@ -83,7 +81,7 @@ fn require_success(status: process::ExitStatus) -> Result<()> { if status.success() { Ok(()) } else { - Err(io::Error::new(io::ErrorKind::Other, "dialog failed")) + Err(Error::from(("dialog", status))) } } @@ -93,16 +91,10 @@ fn get_choice(status: process::ExitStatus) -> Result { 0 => Ok(Choice::Yes), 1 => Ok(Choice::No), 255 => Ok(Choice::Cancel), - code => Err(io::Error::new( - io::ErrorKind::Other, - format!("Could not execute dialog: {}", code), - )), + _ => Err(Error::from(("dialog", status))), } } else { - Err(io::Error::new( - io::ErrorKind::Other, - "dialog was terminated by a signal", - )) + Err(Error::from(("dialog", status))) } } @@ -110,25 +102,17 @@ fn get_stderr(output: process::Output) -> Result> { if output.status.success() { String::from_utf8(output.stderr) .map(|s| Some(s)) - .map_err(|_| { - io::Error::new(io::ErrorKind::Other, "Input contained invalid UTF-8 bytes") - }) + .map_err(|err| Error::from(err)) } else { if let Some(code) = output.status.code() { match code { 0 => Ok(None), 1 => Ok(None), 255 => Ok(None), - code => Err(io::Error::new( - io::ErrorKind::Other, - format!("Could not execute dialog: {}", code), - )), + _ => Err(Error::from(("dialog", output.status))), } } else { - Err(io::Error::new( - io::ErrorKind::Other, - "dialog was terminated by a signal", - )) + Err(Error::from(("dialog", output.status))) } } } diff --git a/src/backends/mod.rs b/src/backends/mod.rs index 12a178b..fd0ddcc 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -5,7 +5,7 @@ mod dialog; pub use crate::backends::dialog::Dialog; -use std::io::Result; +use crate::Result; /// A dialog backend. /// diff --git a/src/lib.rs b/src/lib.rs index b51a3cc..422252b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,7 +79,60 @@ /// [`Backend`]: trait.Backend.html pub mod backends; -use std::io::Result; +use std::io; +use std::process; +use std::result; +use std::str; +use std::string; + +/// A result returned by `dialog`. +pub type Result = result::Result; + +/// An error returned by `dialog`. +#[derive(Debug)] +pub enum Error { + /// A general error with an error message. + Error(String), + /// An input or output error. + IoError(io::Error), + /// An UTF-8 error. + Utf8Error(str::Utf8Error), +} + +impl From<&str> for Error { + fn from(string: &str) -> Error { + Error::Error(string.to_string()) + } +} + +impl From for Error { + fn from(error: io::Error) -> Error { + Error::IoError(error) + } +} + +impl From for Error { + fn from(error: str::Utf8Error) -> Error { + Error::Utf8Error(error) + } +} + +impl From for Error { + fn from(error: string::FromUtf8Error) -> Error { + Error::Utf8Error(error.utf8_error()) + } +} + +impl From<(&str, process::ExitStatus)> for Error { + fn from(data: (&str, process::ExitStatus)) -> Error { + let (command, status) = data; + let msg = match status.code() { + Some(code) => format!("Command {} failed with exit status {}", command, code), + None => format!("Command {} was terminated by a signal", command), + }; + Error::Error(msg) + } +} /// A dialog box that can be shown using a backend. /// -- cgit v1.2.3