1use std::any::Any;
16
17use common_error::ext::ErrorExt;
18use common_error::status_code::StatusCode;
19use common_macro::stack_trace_debug;
20use config::ConfigError;
21use snafu::{Location, Snafu};
22
23pub type Result<T> = std::result::Result<T, Error>;
24
25#[derive(Snafu)]
26#[snafu(visibility(pub))]
27#[stack_trace_debug]
28pub enum Error {
29 #[snafu(display("Failed to load layered config"))]
30 LoadLayeredConfig {
31 #[snafu(source)]
32 error: ConfigError,
33 #[snafu(implicit)]
34 location: Location,
35 },
36
37 #[snafu(display("Failed to serde json"))]
38 SerdeJson {
39 #[snafu(source)]
40 error: serde_json::error::Error,
41 #[snafu(implicit)]
42 location: Location,
43 },
44
45 #[snafu(display("Failed to serialize options to TOML"))]
46 TomlFormat {
47 #[snafu(source)]
48 error: toml::ser::Error,
49 #[snafu(implicit)]
50 location: Location,
51 },
52
53 #[snafu(display("Failed to watch file: {}", path))]
54 FileWatch {
55 path: String,
56 #[snafu(source)]
57 error: notify::Error,
58 #[snafu(implicit)]
59 location: Location,
60 },
61
62 #[snafu(display("Invalid path '{}': expected a file, not a directory", path))]
63 InvalidPath {
64 path: String,
65 #[snafu(implicit)]
66 location: Location,
67 },
68
69 #[snafu(display(
70 "Invalid environment variable key '{key}': '{target}' is a sequence that cannot be \
71 overridden as a whole; address one of its entries with '{target}__<TAG>__<FIELD>'"
72 ))]
73 TaggedSeqMissingTag {
74 key: String,
75 target: String,
76 #[snafu(implicit)]
77 location: Location,
78 },
79
80 #[snafu(display(
81 "Invalid environment variable key '{key}': '{tag}' is a numeric index, but '{target}' \
82 is addressed by tag name; use '{target}__<TAG>__<FIELD>' instead, e.g. \
83 '{target}__MITO__<FIELD>'"
84 ))]
85 TaggedSeqNumericTag {
86 key: String,
87 tag: String,
88 target: String,
89 #[snafu(implicit)]
90 location: Location,
91 },
92
93 #[snafu(display(
94 "Invalid environment variable key '{key}': the entry '{tag}' of '{target}' needs a \
95 field to override; use '{target}__<TAG>__<FIELD>' instead"
96 ))]
97 TaggedSeqMissingField {
98 key: String,
99 tag: String,
100 target: String,
101 #[snafu(implicit)]
102 location: Location,
103 },
104
105 #[snafu(display(
106 "Invalid environment variable key '{key}': another environment variable sets '{path}' \
107 as a whole, so this key cannot set a field below it; set either the whole '{path}' or \
108 its fields, not both"
109 ))]
110 TaggedSeqOverridesConflict {
111 key: String,
112 path: String,
113 #[snafu(implicit)]
114 location: Location,
115 },
116
117 #[snafu(display(
118 "'{path}' cannot be overridden from the environment: its default value is not a table, \
119 so a field below it cannot be set"
120 ))]
121 TaggedSeqNotATable {
122 path: String,
123 #[snafu(implicit)]
124 location: Location,
125 },
126
127 #[snafu(display(
128 "'{key}' is registered as a sequence of tagged tables, but it is not a top-level field \
129 of the options; the default entries to merge onto are looked up by literal key"
130 ))]
131 TaggedSeqNotTopLevel {
132 key: String,
133 #[snafu(implicit)]
134 location: Location,
135 },
136
137 #[snafu(display(
138 "The default value of '{target}' is not a sequence of single-key tables: {reason}"
139 ))]
140 TaggedSeqInvalidDefault {
141 target: String,
142 reason: String,
143 #[snafu(implicit)]
144 location: Location,
145 },
146}
147
148impl ErrorExt for Error {
149 fn status_code(&self) -> StatusCode {
150 match self {
151 Error::TomlFormat { .. }
152 | Error::LoadLayeredConfig { .. }
153 | Error::FileWatch { .. }
154 | Error::InvalidPath { .. }
155 | Error::TaggedSeqMissingTag { .. }
156 | Error::TaggedSeqNumericTag { .. }
157 | Error::TaggedSeqMissingField { .. }
158 | Error::TaggedSeqOverridesConflict { .. }
159 | Error::TaggedSeqNotATable { .. }
160 | Error::TaggedSeqNotTopLevel { .. }
161 | Error::TaggedSeqInvalidDefault { .. } => StatusCode::InvalidArguments,
162 Error::SerdeJson { .. } => StatusCode::Unexpected,
163 }
164 }
165
166 fn as_any(&self) -> &dyn Any {
167 self
168 }
169}