Set up a mock database for the sled example

This commit is contained in:
Savanni D'Gerinel 2023-10-10 22:10:56 -04:00
parent 911f4ad81e
commit d0f6a042e4
7 changed files with 114 additions and 2 deletions

7
Cargo.lock generated
View File

@ -756,6 +756,13 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "error-training"
version = "0.1.0"
dependencies = [
"thiserror",
]
[[package]] [[package]]
name = "etcetera" name = "etcetera"
version = "0.8.0" version = "0.8.0"

View File

@ -7,6 +7,7 @@ members = [
"cyberpunk-splash", "cyberpunk-splash",
"dashboard", "dashboard",
"emseries", "emseries",
"error-training",
"file-service", "file-service",
"fluent-ergonomics", "fluent-ergonomics",
"geo-types", "geo-types",

View File

@ -10,6 +10,7 @@ RUST_ALL_TARGETS=(
"cyberpunk-splash" "cyberpunk-splash"
"dashboard" "dashboard"
"emseries" "emseries"
"error-training"
"file-service" "file-service"
"fluent-ergonomics" "fluent-ergonomics"
"geo-types" "geo-types"

17
error-training/Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "error-training"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "error_training"
path = "src/lib.rs"
[[bin]]
name = "error-training"
path = "src/main.rs"
[dependencies]
thiserror = { version = "1" }

62
error-training/src/lib.rs Normal file
View File

@ -0,0 +1,62 @@
use thiserror::Error;
#[derive(Clone, Debug, Error, PartialEq)]
pub enum FatalError {
#[error("Database corruption detected")]
DatabaseCorruption,
}
#[derive(Clone, Debug, Error, PartialEq)]
pub enum MathError {
#[error("divide by zero is not defined")]
DivideByZero,
#[error("result exceeds maxint")]
ExceedsMaxint,
#[error("result exceeds minint")]
ExceedsMinint,
}
#[derive(Clone, Debug, Error, PartialEq)]
pub enum DatabaseError {
#[error("value not found")]
NotFound,
}
pub mod sled {
//! Sled-style error handling is based on Result<Result<Value, LocalError>, FatalError>.
//! FatalErrors do not get resolved. LocalErrors get bubbled up until they can be handled.
use super::*;
use std::collections::HashMap;
pub struct DB(HashMap<String, i8>);
impl DB {
pub fn new(lst: Vec<(String, i8)>) -> Self {
Self(lst.into_iter().collect::<HashMap<String, i8>>())
}
/// Retrieve a value from the database. Throw a fatal error with the "fail" key, but
/// otherwise return either the value or DatabaseError::NotFound.
///
/// ```rust
/// use error_training::{*, sled::*};
///
/// let db = DB::new(vec![("a".to_owned(), 15), ("b".to_owned(), 0)]);
/// assert_eq!(db.get("fail"), Err(FatalError::DatabaseCorruption));
/// assert_eq!(db.get("a"), Ok(Ok(15)));
/// assert_eq!(db.get("c"), Ok(Err(DatabaseError::NotFound)));
/// ```
pub fn get(&self, key: &str) -> Result<Result<i8, DatabaseError>, FatalError> {
if key == "fail" {
Err(FatalError::DatabaseCorruption)
} else {
Ok(self.0.get(key).copied().ok_or(DatabaseError::NotFound))
}
}
}
pub fn run() {}
}

View File

@ -0,0 +1,26 @@
//! Error handling practice.
//!
//! The purpose of this crate is to demonstrate error handling in a couple of different scenarios
//! so that I have clear templates to refer when doing development, instead of hand-waving or
//! putting error handling off into the unspecified future.
//!
//! I am going to demonstrate error handling in the style of [Error Handling in a
//! Correctness-Critical Rust Project | sled-rs.github.io](https://sled.rs/errors.html) and in my
//! reformulation of it using Flow.
//!
//! I will also test out additional libraries in the same scenarios:
//!
//! - anyhow
//!
//! A database exists with some numbers. Mathmatical calculations will be performed on those
//! numbers. Some calculations are invalid and should fail. In some cases, those should be reported
//! to the user, and in other cases those can be recovered. Sometimes a calculation needs to be
//! performed on a value that doesn't exist, which is also a failure. However, sometimes, the
//! database will detect corruption, wich is fatal and should terminate the "app".
//!
//! In these scenarios, the "app" is a top-level function which runs the scenario. This particular
//! app should never crash, just show where crashes would happen.
fn main() {
println!("Hello, world!");
}

View File

@ -18,8 +18,6 @@ path = "src/main.rs"
name = "auth-cli" name = "auth-cli"
path = "src/bin/cli.rs" path = "src/bin/cli.rs"
[target.auth-cli.dependencies]
[dependencies] [dependencies]
base64ct = { version = "1", features = [ "alloc" ] } base64ct = { version = "1", features = [ "alloc" ] }
build_html = { version = "2" } build_html = { version = "2" }