1use failure::{Backtrace, Context, Fail};
19use std::fmt;
20use std::path::PathBuf;
21use subparse::SubtitleFormat;
22
23#[macro_export]
24macro_rules! define_error {
25 ($error:ident, $errorKind:ident) => {
26 #[derive(Debug)]
27 pub struct $error {
28 inner: Context<$errorKind>,
29 }
30
31 impl Fail for $error {
32 fn name(&self) -> Option<&str> {
33 self.inner.name()
34 }
35
36 fn cause(&self) -> Option<&dyn Fail> {
37 self.inner.cause()
38 }
39
40 fn backtrace(&self) -> Option<&Backtrace> {
41 self.inner.backtrace()
42 }
43 }
44
45 impl fmt::Display for $error {
46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47 fmt::Display::fmt(&self.inner, f)
48 }
49 }
50
51 #[allow(dead_code)]
52 impl $error {
53 pub fn kind(&self) -> &$errorKind {
54 self.inner.get_context()
55 }
56 }
57
58 #[allow(dead_code)]
59 impl $errorKind {
60 pub fn into_error(self) -> $error {
61 $error {
62 inner: Context::new(self),
63 }
64 }
65 }
66
67 impl From<$errorKind> for $error {
68 fn from(kind: $errorKind) -> $error {
69 $error {
70 inner: Context::new(kind),
71 }
72 }
73 }
74
75 impl From<Context<$errorKind>> for $error {
76 fn from(inner: Context<$errorKind>) -> $error {
77 $error { inner: inner }
78 }
79 }
80 };
81}
82
83define_error!(InputFileError, InputFileErrorKind);
84
85#[derive(Clone, Eq, PartialEq, Debug, Fail)]
86pub enum InputFileErrorKind {
87 VideoFile(PathBuf),
88 SubtitleFile(PathBuf),
89}
90
91impl fmt::Display for InputFileErrorKind {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 match self {
94 InputFileErrorKind::VideoFile(p) => write!(f, "processing video file '{}' failed", p.display()),
95 InputFileErrorKind::SubtitleFile(p) => write!(f, "processing subtitle file '{}' failed", p.display()),
96 }
97 }
98}
99
100define_error!(FileOperationError, FileOperationErrorKind);
101
102#[derive(Clone, Eq, PartialEq, Debug, Fail)]
103pub enum FileOperationErrorKind {
104 FileOpen { path: PathBuf },
105 FileRead { path: PathBuf },
106 FileWrite { path: PathBuf },
107}
108
109impl fmt::Display for FileOperationErrorKind {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 match self {
112 FileOperationErrorKind::FileOpen { path } => write!(f, "failed to open file '{}'", path.display()),
113 FileOperationErrorKind::FileRead { path } => write!(f, "failed to read file '{}'", path.display()),
114 FileOperationErrorKind::FileWrite { path } => write!(f, "failed to read file '{}'", path.display()),
115 }
116 }
117}
118
119define_error!(InputVideoError, InputVideoErrorKind);
120
121#[derive(Clone, Eq, PartialEq, Debug, Fail)]
122pub enum InputVideoErrorKind {
123 FailedToDecode { path: PathBuf },
124 VadAnalysisFailed,
125}
126
127impl fmt::Display for InputVideoErrorKind {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 match self {
130 InputVideoErrorKind::FailedToDecode { path } => {
131 write!(f, "failed to extract voice segments from file '{}'", path.display())
132 }
133 InputVideoErrorKind::VadAnalysisFailed => write!(f, "failed to analyse audio segment for voice activity"),
134 }
135 }
136}
137
138define_error!(InputSubtitleError, InputSubtitleErrorKind);
139
140#[derive(Clone, Eq, PartialEq, Debug, Fail)]
141pub enum InputSubtitleErrorKind {
142 ReadingSubtitleFileFailed(PathBuf),
143 UnknownSubtitleFormat(PathBuf),
144 ParsingSubtitleFailed(PathBuf),
145 RetreivingSubtitleLinesFailed(PathBuf),
146}
147
148impl fmt::Display for InputSubtitleErrorKind {
149 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150 match self {
151 InputSubtitleErrorKind::ReadingSubtitleFileFailed(path) => {
152 write!(f, "reading subtitle file '{}' failed", path.display())
153 }
154 InputSubtitleErrorKind::UnknownSubtitleFormat(path) => {
155 write!(f, "unknown subtitle format for file '{}'", path.display())
156 }
157 InputSubtitleErrorKind::ParsingSubtitleFailed(path) => {
158 write!(f, "parsing subtitle file '{}' failed", path.display())
159 }
160 InputSubtitleErrorKind::RetreivingSubtitleLinesFailed(path) => {
161 write!(f, "retreiving subtitle file '{}' failed", path.display())
162 }
163 }
164 }
165}
166
167define_error!(InputArgumentsError, InputArgumentsErrorKind);
168
169#[derive(Clone, PartialEq, Debug, Fail)]
170pub enum InputArgumentsErrorKind {
171 #[fail(
172 display = "expected value '{}' to be in range '{}'-'{}', found value '{}'",
173 argument_name, min, max, value
174 )]
175 ValueNotInRange {
176 argument_name: String,
177 min: f64,
178 max: f64,
179 value: f64,
180 },
181 #[fail(display = "expected positive number for '{}', found '{}'", argument_name, value)]
182 ExpectedPositiveNumber { argument_name: String, value: i64 },
183
184 #[fail(display = "expected non-negative number for '{}', found '{}'", argument_name, value)]
185 ExpectedNonNegativeNumber { argument_name: String, value: f64 },
186
187 #[fail(display = "argument '{}' with value '{}' could not be parsed", argument_name, value)]
188 ArgumentParseError { argument_name: String, value: String },
189}
190
191define_error!(TopLevelError, TopLevelErrorKind);
192
193pub enum TopLevelErrorKind {
194 FileFormatMismatch {
195 input_file_path: PathBuf,
196 output_file_path: PathBuf,
197 input_file_format: SubtitleFormat,
198 },
199 FailedToUpdateSubtitle,
200 FailedToGenerateSubtitleData,
201 FailedToInstantiateSubtitleFile,
202}
203
204impl fmt::Display for TopLevelErrorKind {
205 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 match self {
207 TopLevelErrorKind::FileFormatMismatch { input_file_path, output_file_path, input_file_format } => write!(f, "output file '{}' seems to have a different format than input file '{}' with format '{}' (this program does not perform conversions)", output_file_path.display(), input_file_path.display(), input_file_format.get_name()),
208 TopLevelErrorKind::FailedToUpdateSubtitle => write!(f, "failed to change lines in the subtitle"),
209 TopLevelErrorKind::FailedToGenerateSubtitleData => write!(f, "failed to generate data for subtitle"),
210 TopLevelErrorKind::FailedToInstantiateSubtitleFile => write!(f, "failed to instantiate subtitle file"),
211 }
212 }
213}