#![allow(dead_code)]
use crate::utils::error::{GatewayError, Result};
use tracing::{error, warn};
pub trait ResultExt<T> {
fn unwrap_or_log_default(self, context: &str) -> T
where
T: Default;
fn unwrap_or_log(self, default: T, context: &str) -> T;
fn with_context(self, context: &str) -> Result<T>;
fn log_and_continue(self, context: &str) -> Option<T>;
}
impl<T> ResultExt<T> for Result<T> {
fn unwrap_or_log_default(self, context: &str) -> T
where
T: Default,
{
match self {
Ok(value) => value,
Err(e) => {
error!("Error in {}: {}. Using default value.", context, e);
T::default()
}
}
}
fn unwrap_or_log(self, default: T, context: &str) -> T {
match self {
Ok(value) => value,
Err(e) => {
error!("Error in {}: {}. Using fallback value.", context, e);
default
}
}
}
fn with_context(self, context: &str) -> Result<T> {
self.map_err(|e| GatewayError::Internal(format!("{}: {}", context, e)))
}
fn log_and_continue(self, context: &str) -> Option<T> {
match self {
Ok(value) => Some(value),
Err(e) => {
warn!("Non-fatal error in {}: {}. Continuing...", context, e);
None
}
}
}
}
pub trait OptionExt<T> {
fn ok_or_context(self, context: &str) -> Result<T>;
fn unwrap_or_log_default(self, context: &str) -> T
where
T: Default;
}
impl<T> OptionExt<T> for Option<T> {
fn ok_or_context(self, context: &str) -> Result<T> {
self.ok_or_else(|| GatewayError::Internal(format!("Missing required value: {}", context)))
}
fn unwrap_or_log_default(self, context: &str) -> T
where
T: Default,
{
match self {
Some(value) => value,
None => {
warn!("Missing value in {}, using default", context);
T::default()
}
}
}
}
pub trait SafeConvert<T> {
fn safe_convert(self, context: &str) -> Result<T>;
}
impl SafeConvert<usize> for u32 {
fn safe_convert(self, context: &str) -> Result<usize> {
usize::try_from(self).map_err(|e| {
GatewayError::Internal(format!("Numeric conversion failed in {}: {}", context, e))
})
}
}
impl SafeConvert<u32> for usize {
fn safe_convert(self, context: &str) -> Result<u32> {
u32::try_from(self).map_err(|e| {
GatewayError::Internal(format!("Numeric conversion failed in {}: {}", context, e))
})
}
}
#[macro_export]
macro_rules! safe_unwrap {
($expr:expr, $context:expr) => {
match $expr {
Ok(val) => val,
Err(e) => {
tracing::error!("Error in {}: {}", $context, e);
return Err(crate::utils::error::GatewayError::Internal(format!(
"Failed in {}: {}",
$context, e
)));
}
}
};
}
#[macro_export]
macro_rules! safe_unwrap_option {
($expr:expr, $context:expr) => {
match $expr {
Some(val) => val,
None => {
tracing::error!("Missing required value in {}", $context);
return Err(crate::utils::error::GatewayError::Internal(format!(
"Missing required value in {}",
$context
)));
}
}
};
}
pub fn config_error(msg: &str) -> GatewayError {
GatewayError::Config(msg.to_string())
}
pub fn internal_error(msg: &str) -> GatewayError {
GatewayError::Internal(msg.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_result_ext() {
let ok_result: Result<i32> = Ok(42);
let err_result: Result<i32> = Err(GatewayError::Internal("test error".to_string()));
assert_eq!(ok_result.unwrap_or_log_default("test"), 42);
assert_eq!(err_result.unwrap_or_log_default("test"), 0);
let ok_result: Result<i32> = Ok(42);
let err_result: Result<i32> = Err(GatewayError::Internal("test error".to_string()));
assert_eq!(ok_result.unwrap_or_log(99, "test"), 42);
assert_eq!(err_result.unwrap_or_log(99, "test"), 99);
}
#[test]
fn test_option_ext() {
let some_val = Some(42);
let none_val: Option<i32> = None;
assert_eq!(some_val.unwrap_or_log_default("test"), 42);
assert_eq!(none_val.unwrap_or_log_default("test"), 0);
}
#[test]
fn test_safe_convert() {
let val: u32 = 42;
let converted: Result<usize> = val.safe_convert("test conversion");
assert!(converted.is_ok());
assert_eq!(converted.unwrap(), 42);
}
}