wb-cache 0.1.0

Your L1 in-app write-behind cache for various kinds of backends.
Documentation
use std::env;
use std::fmt::Debug;
use std::fmt::Display;
use std::sync::Arc;

use fieldx::error::FieldXError;
use parking_lot::RwLock;
use sea_orm::prelude::*;
use sea_orm::DbErr;
use sea_orm::DeriveActiveEnum;
use sea_orm::EnumIter;
use serde::Deserialize;
use serde::Serialize;
use std::mem;

use super::scriptwriter::steps::Step;

macro_rules! simerr {
    ($fmt:literal $(, $( $tt:tt )+)?) => {
        $crate::test::simulation::types::SimErrorAny::with_anyhow(anyhow::anyhow!($fmt $(, $( $tt )+)?))
    };
}

pub(crate) use simerr;

pub enum SimError {
    Any(SimErrorAny),
    Sim(Arc<SimErrorAny>),
}

impl SimError {
    pub fn new<E>(err: E) -> Self
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        Self::Any(SimErrorAny::new(err))
    }

    pub fn context<C>(&self, context: C)
    where
        C: Display + Send + Sync + 'static,
    {
        match self {
            Self::Any(err) => {
                err.context(context);
            }
            Self::Sim(err) => err.context(context),
        }
    }

    pub fn to_string_with_backtrace<S: Display>(&self, msg: S) -> String {
        match self {
            Self::Any(err) => err.to_string_with_backtrace(msg),
            Self::Sim(err) => err.to_string_with_backtrace(msg),
        }
    }

    pub fn report_with_backtrace<S: Display>(&self, msg: S) {
        match self {
            Self::Any(err) => err.report_with_backtrace(msg),
            Self::Sim(err) => err.report_with_backtrace(msg),
        }
    }
}

impl Debug for SimError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Any(err) => Debug::fmt(err, f),
            Self::Sim(err) => Debug::fmt(err, f),
        }
    }
}

impl Display for SimError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Any(err) => Display::fmt(err, f),
            Self::Sim(err) => Display::fmt(err, f),
        }
    }
}

impl From<anyhow::Error> for SimError {
    fn from(err: anyhow::Error) -> Self {
        Self::Any(SimErrorAny(RwLock::new(err)))
    }
}

impl From<Arc<SimErrorAny>> for SimError {
    fn from(err: Arc<SimErrorAny>) -> Self {
        Self::Sim(err)
    }
}

impl From<SimErrorAny> for SimError {
    fn from(err: SimErrorAny) -> Self {
        Self::Any(err)
    }
}

impl From<DbErr> for SimError {
    fn from(err: DbErr) -> Self {
        Self::Any(SimErrorAny(RwLock::new(anyhow::Error::from(err))))
    }
}

impl From<FieldXError> for SimError {
    fn from(err: FieldXError) -> Self {
        Self::Any(SimErrorAny::from(err))
    }
}

impl From<SimError> for SimErrorAny {
    fn from(err: SimError) -> Self {
        match err {
            SimError::Any(e) => e,
            SimError::Sim(e) => simerr!("{e:?}"),
        }
    }
}

pub type Result<T, ERR = SimErrorAny> = std::result::Result<T, ERR>;

#[derive(Debug)]
pub struct SimErrorAny(RwLock<anyhow::Error>);

impl<E> From<E> for SimErrorAny
where
    E: std::error::Error + Send + Sync + 'static,
{
    fn from(err: E) -> Self {
        Self(RwLock::new(anyhow::Error::new(err)))
    }
}

impl SimErrorAny {
    pub fn new<E>(err: E) -> Self
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        Self(RwLock::new(anyhow::Error::new(err)))
    }

    pub fn with_anyhow(err: anyhow::Error) -> Self {
        Self(RwLock::new(err))
    }

    pub fn context<C>(&self, context: C)
    where
        C: Display + Send + Sync + 'static,
    {
        let mut error = self.0.write();
        let err = mem::replace(&mut *error, anyhow::Error::msg("temp"));
        let err = err.context(context);
        *error = err;
    }

    pub fn with_context<C>(self, context: C) -> Self
    where
        C: Display + Send + Sync + 'static,
    {
        self.context(context);
        self
    }

    pub fn to_string_with_backtrace<S: Display>(&self, msg: S) -> String {
        let inner = self.0.read();
        if env::var("RUST_BACKTRACE").is_ok() {
            format!("{msg}: {inner:?}")
        }
        else {
            format!("{msg}: {inner:#}")
        }
    }

    pub fn report_with_backtrace<S: Display>(&self, msg: S) {
        let inner = self.0.read();
        if env::var("RUST_BACKTRACE").is_ok() {
            eprintln!("{msg}: {inner:?}");
        }
        else {
            eprintln!("{msg}: {inner:#}");
        }
    }
}

impl Display for SimErrorAny {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let error = self.0.read();
        Display::fmt(&*error, f)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "String(StringLen::N(20))")]
pub enum OrderStatus {
    #[sea_orm(string_value = "New")]
    #[serde(rename = "n")]
    New,
    #[sea_orm(string_value = "Backordered")]
    #[serde(rename = "b")]
    Backordered,
    // Re-check if we can proceed with a backordered order.
    #[sea_orm(string_value = "Recheck")]
    #[serde(rename = "c")]
    Recheck,
    #[sea_orm(string_value = "Pending")]
    #[serde(rename = "p")]
    Pending,
    #[sea_orm(string_value = "Shipped")]
    #[serde(rename = "s")]
    Shipped,
    #[sea_orm(string_value = "Refunded")]
    #[serde(rename = "r")]
    Refunded,
}

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Script {
    #[serde(rename = "l")]
    pub length: usize,
    #[serde(rename = "s")]
    pub steps:  Vec<Step>,
}