Skip to content

Commit 7022fc0

Browse files
committed
Restructure error handling
1 parent fa68893 commit 7022fc0

File tree

7 files changed

+216
-60
lines changed

7 files changed

+216
-60
lines changed

Cargo.lock

Lines changed: 71 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@ license = "MIT"
1111
edition = "2018"
1212
build = "build.rs"
1313

14-
[dependencies]
15-
clap = "2.33.0"
16-
indoc = "0.3.1"
17-
nix = "0.13.0"
18-
19-
[build-dependencies]
20-
clap = "2.33.0"
21-
indoc = "0.3.1"
22-
2314
[package.metadata.deb]
2415
maintainer = "Maximilian Luz <[email protected]>"
2516
license-file = ["LICENSE", "0"]
@@ -35,3 +26,13 @@ assets = [
3526
["target/_surface", "usr/share/zsh/vendor-completions/_surface", "644"],
3627
["target/surface.fish", "usr/share/fish/completions/surface.fish", "644"],
3728
]
29+
30+
[dependencies]
31+
clap = "2.33.0"
32+
indoc = "0.3.1"
33+
nix = "0.13.0"
34+
failure = "0.1.5"
35+
36+
[build-dependencies]
37+
clap = "2.33.0"
38+
indoc = "0.3.1"

src/error.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use failure::{Context, Fail, Backtrace};
2+
3+
4+
pub type Result<T> = std::result::Result<T, Error>;
5+
pub use failure::ResultExt;
6+
7+
#[derive(Debug)]
8+
pub struct Error {
9+
inner: Context<ErrorKind>
10+
}
11+
12+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Fail)]
13+
pub enum ErrorKind {
14+
#[fail(display = "I/O failure")]
15+
Io,
16+
17+
#[fail(display = "Received invalid data")]
18+
InvalidData,
19+
20+
#[fail(display = "Cannot access device")]
21+
DeviceAccess,
22+
}
23+
24+
25+
impl Error {
26+
pub fn kind(&self) -> ErrorKind {
27+
*self.inner.get_context()
28+
}
29+
30+
pub fn iter_causes(&self) -> failure::Causes {
31+
((&self.inner) as &dyn Fail).iter_causes()
32+
}
33+
}
34+
35+
impl From<ErrorKind> for Error {
36+
fn from(kind: ErrorKind) -> Error {
37+
Error { inner: Context::new(kind) }
38+
}
39+
}
40+
41+
impl From<Context<ErrorKind>> for Error {
42+
fn from(inner: Context<ErrorKind>) -> Error {
43+
Error { inner: inner }
44+
}
45+
}
46+
47+
impl Fail for Error {
48+
fn cause(&self) -> Option<&Fail> {
49+
self.inner.cause()
50+
}
51+
52+
fn backtrace(&self) -> Option<&Backtrace> {
53+
self.inner.backtrace()
54+
}
55+
}
56+
57+
impl std::fmt::Display for Error {
58+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
59+
std::fmt::Display::fmt(&self.inner, f)
60+
}
61+
}

src/main.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use std::io::Result;
2-
1+
mod error;
32
mod cli;
43
mod sys;
54

5+
use crate::error::Result;
6+
67

78
fn main() {
89
let matches = cli::app().get_matches();
@@ -16,7 +17,11 @@ fn main() {
1617
};
1718

1819
if let Err(e) = result {
19-
eprintln!("Error: {}", e);
20+
eprintln!("Error: {}.", e.kind());
21+
22+
for cause in e.iter_causes() {
23+
eprintln!(" {}.", cause);
24+
}
2025
}
2126
}
2227

src/sys/dgpu.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::fs::OpenOptions;
22
use std::path::{Path, PathBuf};
3-
use std::io::{Result, Error, ErrorKind, Read, Write};
3+
use std::io::{Read, Write};
4+
5+
use crate::error::{Error, ErrorKind, Result, ResultExt};
46

57

68
#[derive(Debug, Copy, Clone)]
@@ -32,12 +34,15 @@ impl std::fmt::Display for PowerState {
3234
}
3335
}
3436

37+
38+
#[derive(Debug)]
39+
pub struct InvalidPowerStateError;
40+
3541
impl std::str::FromStr for PowerState {
36-
type Err = String;
42+
type Err = InvalidPowerStateError;
3743

3844
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
39-
PowerState::from_str(s)
40-
.ok_or(format!("invalid power state: '{}'", s))
45+
PowerState::from_str(s).ok_or(InvalidPowerStateError)
4146
}
4247
}
4348

@@ -55,7 +60,9 @@ impl Device {
5560
if path.as_ref().is_dir() {
5661
Ok(Device { path: path.as_ref().to_owned() })
5762
} else {
58-
Err(Error::new(ErrorKind::NotFound, "No Surface dGPU device found"))
63+
Err(failure::err_msg("Surface dGPU hot-plug device not found"))
64+
.context(ErrorKind::DeviceAccess)
65+
.map_err(|e| e.into())
5966
}
6067
}
6168

@@ -64,34 +71,35 @@ impl Device {
6471

6572
let mut file = OpenOptions::new()
6673
.read(true)
67-
.open(self.path.as_path().join("dgpu_power"))?;
74+
.open(self.path.as_path().join("dgpu_power"))
75+
.context(ErrorKind::DeviceAccess)?;
6876

6977
let mut buf = [0; 4];
70-
let len = file.read(&mut buf)?;
78+
let len = file.read(&mut buf).context(ErrorKind::Io)?;
7179

7280
let state = CStr::from_bytes_with_nul(&buf[0..len+1])
73-
.map_err(|_| Error::new(ErrorKind::InvalidData, "Device returned invalid data"))?
74-
.to_str()
75-
.map_err(|_| Error::new(ErrorKind::InvalidData, "Device returned invalid data"))?
81+
.context(ErrorKind::InvalidData)?
82+
.to_str().context(ErrorKind::InvalidData)?
7683
.trim();
7784

7885
PowerState::from_str(state)
79-
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "Device returned invalid data"))
86+
.ok_or_else(|| Error::from(ErrorKind::InvalidData))
8087
}
8188

8289
pub fn set_power(&self, state: PowerState) -> Result<()> {
8390
let state = state.as_str().as_bytes();
8491

8592
let mut file = OpenOptions::new()
8693
.write(true)
87-
.open(self.path.as_path().join("dgpu_power"))?;
94+
.open(self.path.as_path().join("dgpu_power"))
95+
.context(ErrorKind::DeviceAccess)?;
8896

89-
let len = file.write(state)?;
97+
let len = file.write(state).context(ErrorKind::Io)?;
9098

9199
if len == state.len() {
92100
Ok(())
93101
} else {
94-
Err(Error::new(ErrorKind::Other, "Failed to write to device"))
102+
Err(Error::from(ErrorKind::Io))
95103
}
96104
}
97105
}

0 commit comments

Comments
 (0)