1use std::fmt;
2use std::path::{Path, PathBuf};
3
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct DocError {
6 pub file: PathBuf,
7 pub key: String,
8 pub message: String,
9}
10
11impl DocError {
12 pub fn new(file: impl AsRef<Path>, key: impl Into<String>, message: impl Into<String>) -> Self {
13 DocError {
14 file: file.as_ref().to_path_buf(),
15 key: key.into(),
16 message: message.into(),
17 }
18 }
19}
20
21impl fmt::Display for DocError {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 let file = self.file.display();
24 if self.key.is_empty() {
25 write!(f, "{file}: {}", self.message)
26 } else {
27 write!(f, "{file}: {}: {}", self.key, self.message)
28 }
29 }
30}
31
32impl std::error::Error for DocError {}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn an_error_names_its_file_and_key() {
40 let error = DocError::new("a.toml", "object[crate].at", "no key `at`");
41 assert_eq!(error.to_string(), "a.toml: object[crate].at: no key `at`");
42 let bare = DocError::new("a.toml", "", "does not parse");
43 assert_eq!(bare.to_string(), "a.toml: does not parse");
44 }
45}