summaryrefslogtreecommitdiffstats
path: root/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/error.rs')
-rw-r--r--src/error.rs194
1 files changed, 194 insertions, 0 deletions
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..6b567a2
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,194 @@
+use std::error::Error;
+use std::borrow::Cow;
+use std::result;
+use std::fmt;
+use serde::de;
+use nom;
+
+#[derive(Debug)]
+pub enum Unexpected {
+ Bool(bool),
+ Integer(i64),
+ Float(f64),
+ Str(String),
+ Unit,
+ Seq,
+ Map
+}
+
+impl fmt::Display for Unexpected {
+ fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+ match *self {
+ Unexpected::Bool(b) => write!(f, "boolean `{}`", b),
+ Unexpected::Integer(i) => write!(f, "integer `{}`", i),
+ Unexpected::Float(v) => write!(f, "floating point `{}`", v),
+ Unexpected::Str(ref s) => write!(f, "string {:?}", s),
+ Unexpected::Unit => write!(f, "unit value"),
+ Unexpected::Seq => write!(f, "sequence"),
+ Unexpected::Map => write!(f, "map"),
+ }
+ }
+}
+
+/// Represents all possible errors that can occur when working with
+/// configuration.
+pub enum ConfigError {
+ /// Configuration is frozen and no further mutations can be made.
+ Frozen,
+
+ /// Configuration property was not found
+ NotFound(String),
+
+ /// Configuration path could not be parsed.
+ PathParse(nom::ErrorKind),
+
+ /// Configuration could not be parsed from file.
+ FileParse {
+ /// The URI used to access the file (if not loaded from a string).
+ /// Example: `/path/to/config.json`
+ uri: Option<String>,
+
+ /// The captured error from attempting to parse the file in its desired format.
+ /// This is the actual error object from the library used for the parsing.
+ cause: Box<Error>
+ },
+
+ /// Value could not be converted into the requested type.
+ Type {
+ /// The URI that references the source that the value came from.
+ /// Example: `/path/to/config.json` or `Environment` or `etcd://localhost`
+ // TODO: Why is this called Origin but FileParse has a uri field?
+ origin: Option<String>,
+
+ /// What we found when parsing the value
+ unexpected: Unexpected,
+
+ /// What was expected when parsing the value
+ expected: &'static str,
+
+ /// The key in the configuration hash of this value (if available where the
+ /// error is generated).
+ key: Option<String>,
+ },
+
+ /// Custom message
+ Message(String),
+
+ /// Unadorned error from a foreign origin.
+ Foreign(Box<Error>),
+}
+
+impl ConfigError {
+ // FIXME: pub(crate)
+ #[doc(hidden)]
+ pub fn invalid_type(origin: Option<String>, unexpected: Unexpected, expected: &'static str) -> Self {
+ ConfigError::Type {
+ origin: origin,
+ unexpected: unexpected,
+ expected: expected,
+ key: None,
+ }
+ }
+
+ // FIXME: pub(crate)
+ #[doc(hidden)]
+ pub fn extend_with_key(self, key: &str) -> Self {
+ match self {
+ ConfigError::Type { origin, unexpected, expected, .. } => {
+ ConfigError::Type {
+ origin: origin,
+ unexpected: unexpected,
+ expected: expected,
+ key: Some(key.into()),
+ }
+ }
+
+ _ => self,
+ }
+ }
+}
+
+/// Alias for a `Result` with the error type set to `ConfigError`.
+pub type Result<T> = result::Result<T, ConfigError>;
+
+// Forward Debug to Display for readable panic! messages
+impl fmt::Debug for ConfigError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", *self)
+ }
+}
+
+impl fmt::Display for ConfigError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ ConfigError::Frozen | ConfigError::PathParse(_) => {
+ write!(f, "{}", self.description())
+ }
+
+ ConfigError::Message(ref s) => {
+ write!(f, "{}", s)
+ }
+
+ ConfigError::Foreign(ref cause) => {
+ write!(f, "{}", cause)
+ }
+
+ ConfigError::NotFound(ref key) => {
+ write!(f, "configuration property {:?} not found", key)
+ }
+
+ ConfigError::Type { ref origin, ref unexpected, expected, ref key } => {
+ write!(f, "invalid type: {}, expected {}",
+ unexpected, expected)?;
+
+ if let Some(ref key) = *key {
+ write!(f, " for key `{}`", key)?;
+ }
+
+ if let Some(ref origin) = *origin {
+ write!(f, " in {}", origin)?;
+ }
+
+ Ok(())
+ }
+
+ ConfigError::FileParse { ref cause, ref uri } => {
+ write!(f, "{}", cause)?;
+
+ if let Some(ref uri) = *uri {
+ write!(f, " in {}", uri)?;
+ }
+
+ Ok(())
+ }
+ }
+ }
+}
+
+impl Error for ConfigError {
+ fn description(&self) -> &str {
+ match *self {
+ ConfigError::Frozen => "configuration is frozen",
+ ConfigError::NotFound(_) => "configuration property not found",
+ ConfigError::Type { .. } => "invalid type",
+ ConfigError::Foreign(ref cause) | ConfigError::FileParse { ref cause, .. } => cause.description(),
+ ConfigError::PathParse(ref kind) => kind.description(),
+
+ _ => "configuration error",
+ }
+ }
+
+ fn cause(&self) -> Option<&Error> {
+ match *self {
+ ConfigError::Foreign(ref cause) | ConfigError::FileParse { ref cause, .. } => Some(cause.as_ref()),
+
+ _ => None
+ }
+ }
+}
+
+impl de::Error for ConfigError {
+ fn custom<T: fmt::Display>(msg: T) -> Self {
+ ConfigError::Message(msg.to_string())
+ }
+}