1use std::{fmt, path::PathBuf};
2
3use crate::tree::{ConfigPath, Origin};
4
5#[derive(Debug)]
7pub enum ConfigError {
8 OverwriteNotAllowed {
13 position: ConfigPath,
14 current_origin: Option<Origin>,
15 incoming_origin: Option<Origin>,
16 },
17
18 MissingRequiredValue { position: ConfigPath },
21
22 CouldNotRead {
24 path: PathBuf,
25 cause: std::io::Error,
26 },
27
28 CouldNotParse {
30 path: PathBuf,
31 cause: toml::de::Error,
32 },
33
34 DirectiveNotAllowed { path: PathBuf },
37
38 MismatchedVariants {
40 position: ConfigPath,
41 current: &'static str,
42 incoming: &'static str,
43 },
44}
45
46impl fmt::Display for ConfigError {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 Self::OverwriteNotAllowed {
50 position,
51 current_origin,
52 incoming_origin,
53 } => write!(
54 f,
55 "`{position}` is set by both {} and {}",
56 Described(current_origin),
57 Described(incoming_origin),
58 ),
59 Self::MissingRequiredValue { position } => {
60 write!(f, "`{position}` is required, but was never set")
61 }
62 Self::CouldNotRead { path, cause } => {
63 write!(f, "could not read `{}`: {cause}", path.display())
64 }
65 Self::CouldNotParse { path, cause } => {
66 write!(f, "could not parse `{}`: {cause}", path.display())
67 }
68 Self::DirectiveNotAllowed { path } => write!(
69 f,
70 "`{}` sets `use-system-config`, which only the main configuration may do",
71 path.display()
72 ),
73 Self::MismatchedVariants {
74 position,
75 current,
76 incoming,
77 } => write!(
78 f,
79 "At {position}, trying to merge {current} with differen variant {incoming}, which is not possible",
80 ),
81 }
82 }
83}
84
85impl std::error::Error for ConfigError {
86 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
87 match self {
88 Self::CouldNotRead { cause, .. } => Some(cause),
89 Self::CouldNotParse { cause, .. } => Some(cause),
90 _ => None,
91 }
92 }
93}
94
95struct Described<'a>(&'a Option<Origin>);
98
99impl fmt::Display for Described<'_> {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 match self.0 {
102 Some(Origin::MainConfig(path)) | Some(Origin::SystemConfig(path)) => {
103 write!(f, "`{}`", path.display())
104 }
105 Some(Origin::BuiltInDefault) => write!(f, "the built-in defaults"),
106 None => write!(f, "an unknown document"),
107 }
108 }
109}