midi_file/
error.rs

1//! The `error` module provides the error type used throughout the library.
2
3use snafu::Snafu;
4use std::num::TryFromIntError;
5use std::path::PathBuf;
6
7/// The public Error type for this library.
8#[derive(Debug, Snafu)]
9pub struct Error(LibError);
10
11/// The public Result type for this library.
12pub type Result<T> = std::result::Result<T, Error>;
13
14/// The internal Result type for this library.
15pub(crate) type LibResult<T> = std::result::Result<T, LibError>;
16
17/// The internal Error type for this library.
18#[derive(Debug, Snafu)]
19#[snafu(visibility(pub(crate)))]
20pub(crate) enum LibError {
21    #[snafu(display("{} Error creating file '{}': {}", site, path.display(), source))]
22    Create {
23        site: String,
24        path: PathBuf,
25        source: std::io::Error,
26    },
27
28    #[snafu(display("{}: The MIDI file is invalid: {}", site, description))]
29    InvalidFile { site: String, description: String },
30
31    #[snafu(display("{} unknown error", site))]
32    Other { site: String },
33
34    #[snafu(display("{} Error while reading data: {}", site, source))]
35    Read {
36        site: String,
37        source: crate::byte_iter::ByteError,
38    },
39
40    #[snafu(display("{} Expected a running status byte but found none", site))]
41    RunningStatus { site: String },
42
43    #[snafu(display("{} The string is too long and overflows a u32: {}", site, source))]
44    StringTooLong {
45        site: String,
46        source: TryFromIntError,
47    },
48
49    #[snafu(display("{} There are too many tracks for a 16-byte uint: {}", site, source))]
50    TooManyTracks {
51        site: String,
52        source: TryFromIntError,
53    },
54
55    #[snafu(display("{} The track is too long and overflows a u32: {}", site, source))]
56    TrackTooLong {
57        site: String,
58        source: TryFromIntError,
59    },
60
61    #[snafu(display("{} The '{}' feature is not yet implemented", site, feature))]
62    Unimplemented { site: String, feature: String },
63
64    #[snafu(display("{} Error while writing data: {}", site, source))]
65    Write {
66        site: String,
67        source: std::io::Error,
68    },
69}
70
71impl From<Error> for LibError {
72    fn from(e: Error) -> Self {
73        e.0
74    }
75}
76
77macro_rules! site {
78    () => {
79        format!("{}:{}", file!(), line!())
80    };
81}
82
83macro_rules! io {
84    () => {
85        crate::error::ReadSnafu { site: site!() }
86    };
87}
88
89macro_rules! wr {
90    () => {
91        crate::error::WriteSnafu { site: site!() }
92    };
93}
94
95macro_rules! invalid_file_s {
96    () => {
97        crate::error::InvalidFileSnafu {
98            site: site!(),
99            description: "[no description]",
100        }
101    };
102    ($msg:expr) => {
103        crate::error::InvalidFileSnafu {
104            site: site!(),
105            description: $msg,
106        }
107    };
108    ($fmt:expr, $($arg:expr),+) => {
109        crate::error::InvalidFileSnafu {
110            site: site!(),
111            description: format!($fmt, $($arg),+),
112        }
113    };
114}
115
116macro_rules! invalid_file_e {
117    () => {
118        invalid_file_s!().build()
119    };
120    ($msg:expr) => {
121        invalid_file_s!($msg).build()
122    };
123    ($fmt:expr, $($arg:expr),+) => {
124        invalid_file_s!($fmt, $($arg),+).build()
125    };
126}
127
128macro_rules! invalid_file_r {
129    () => {
130        Err(invalid_file_e!())
131    };
132    ($msg:expr) => {
133        Err(invalid_file_e!($msg))
134    };
135    ($fmt:expr, $($arg:expr),+) => {
136        Err(invalid_file_e!($fmt, $($arg),+))
137    };
138}
139
140macro_rules! invalid_file {
141    () => {
142        return invalid_file_r!();
143    };
144    ($msg:expr) => {
145        return invalid_file_r!($msg)
146    };
147    ($fmt:expr, $($arg:expr),+) => {
148        return invalid_file_r!($fmt, $($arg),+)
149    };
150}
151
152macro_rules! noimpl {
153    ($name:expr) => {
154        return crate::error::UnimplementedSnafu {
155            site: site!(),
156            feature: $name.to_string(),
157        }
158        .fail()
159    };
160}
161
162#[test]
163fn site_test() {
164    let line = line!() + 1;
165    let site = site!();
166    assert!(site.contains("error.rs"));
167    assert!(site.contains(format!("{}", line).as_str()));
168}
169
170#[test]
171fn invalid_file_macros_test_no_message() {
172    fn foo() -> LibResult<u64> {
173        invalid_file!();
174    }
175    let result = foo();
176    assert!(result.is_err());
177    let message = format!("{}", result.err().unwrap());
178    assert!(message.as_str().contains("The MIDI file is invalid"));
179}
180
181#[test]
182fn invalid_file_macros_test_message() {
183    fn foo() -> LibResult<u64> {
184        let flerbin = String::from("flerbin");
185        invalid_file!(flerbin);
186    }
187    let result = foo();
188    assert!(result.is_err());
189    let message = format!("{}", result.err().unwrap());
190    assert!(message.as_str().contains("flerbin"));
191}
192
193#[test]
194fn invalid_file_macros_test_fmt() {
195    fn foo() -> LibResult<u64> {
196        invalid_file!("hello {}, {}", "world", String::from("foo"));
197    }
198    let result = foo();
199    assert!(result.is_err());
200    let message = format!("{}", result.err().unwrap());
201    assert!(message.as_str().contains("hello world, foo"));
202}