about summary refs log tree commit diff
path: root/users/tazjin/finito/finito-postgres/src/error.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2020-06-30T03·35+0100
committerVincent Ambo <mail@tazj.in>2020-06-30T03·35+0100
commit9e7b81391d016d98ef9b5f0c1f3405bdec31133c (patch)
tree5310a4a669f6f163df1969bdc44a2b6198363e84 /users/tazjin/finito/finito-postgres/src/error.rs
parent0380841eb11f6cb200081295107fadbca928bc06 (diff)
parentb7481172252d6f00546e94534b05d011b4105843 (diff)
feat(tazjin/finito): Check in my old Rust state-machine library r/1136
I dug through my archives for this and found a version that, while
unfortunately not the latest implementation, is close enough to the
real thing to show off what Finito did.

This is a Postgres-backed state-machine library for complex
application logic. I wrote this originally for a work purpose in a
previous life, but have always wanted to apply it elsewhere, too.

git-subtree-dir: users/tazjin/finito
git-subtree-mainline: 0380841eb11f6cb200081295107fadbca928bc06
git-subtree-split: b7481172252d6f00546e94534b05d011b4105843
Change-Id: I0de02d6258568447a14870f1a533812a67127763
Diffstat (limited to 'users/tazjin/finito/finito-postgres/src/error.rs')
-rw-r--r--users/tazjin/finito/finito-postgres/src/error.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/users/tazjin/finito/finito-postgres/src/error.rs b/users/tazjin/finito/finito-postgres/src/error.rs
new file mode 100644
index 000000000000..e130d18361f1
--- /dev/null
+++ b/users/tazjin/finito/finito-postgres/src/error.rs
@@ -0,0 +1,109 @@
+//! This module defines error types and conversions for issue that can
+//! occur while dealing with persisted state machines.
+
+use std::result;
+use std::fmt;
+use uuid::Uuid;
+use std::error::Error as StdError;
+
+// errors to chain:
+use postgres::Error as PgError;
+use r2d2_postgres::r2d2::Error as PoolError;
+use serde_json::Error as JsonError;
+
+pub type Result<T> = result::Result<T, Error>;
+
+#[derive(Debug)]
+pub struct Error {
+    pub kind: ErrorKind,
+    pub context: Option<String>,
+}
+
+#[derive(Debug)]
+pub enum ErrorKind {
+    /// Errors occuring during JSON serialization of FSM types.
+    Serialization(String),
+
+    /// Errors occuring during communication with the database.
+    Database(String),
+
+    /// Errors with the database connection pool.
+    DBPool(String),
+
+    /// State machine could not be found.
+    FSMNotFound(Uuid),
+
+    /// Action could not be found.
+    ActionNotFound(Uuid),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use ErrorKind::*;
+        let msg = match &self.kind {
+            Serialization(err) =>
+                format!("JSON serialization error: {}", err),
+
+            Database(err) =>
+                format!("PostgreSQL error: {}", err),
+
+            DBPool(err) =>
+                format!("Database connection pool error: {}", err),
+
+            FSMNotFound(id) =>
+                format!("FSM with ID {} not found", id),
+
+            ActionNotFound(id) =>
+                format!("Action with ID {} not found", id),
+        };
+
+        match &self.context {
+            None => write!(f, "{}", msg),
+            Some(ctx) => write!(f, "{}: {}", ctx, msg),
+        }
+    }
+}
+
+impl StdError for Error {}
+
+impl <E: Into<ErrorKind>> From<E> for Error {
+    fn from(err: E) -> Error {
+        Error {
+            kind: err.into(),
+            context: None,
+        }
+    }
+}
+
+impl From<JsonError> for ErrorKind {
+    fn from(err: JsonError) -> ErrorKind {
+        ErrorKind::Serialization(err.to_string())
+    }
+}
+
+impl From<PgError> for ErrorKind {
+    fn from(err: PgError) -> ErrorKind {
+        ErrorKind::Database(err.to_string())
+    }
+}
+
+impl From<PoolError> for ErrorKind {
+    fn from(err: PoolError) -> ErrorKind {
+        ErrorKind::DBPool(err.to_string())
+    }
+}
+
+/// Helper trait that makes it possible to supply contextual
+/// information with an error.
+pub trait ResultExt<T> {
+    fn context<C: fmt::Display>(self, ctx: C) -> Result<T>;
+}
+
+impl <T, E: Into<Error>> ResultExt<T> for result::Result<T, E> {
+    fn context<C: fmt::Display>(self, ctx: C) -> Result<T> {
+        self.map_err(|err| Error {
+            context: Some(format!("{}", ctx)),
+            .. err.into()
+        })
+    }
+}