1use snafu::Snafu;
4use std::num::TryFromIntError;
5use std::path::PathBuf;
6
7#[derive(Debug, Snafu)]
9pub struct Error(LibError);
10
11pub type Result<T> = std::result::Result<T, Error>;
13
14pub(crate) type LibResult<T> = std::result::Result<T, LibError>;
16
17#[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}