From 492866925c0a5f15943b0b35c8b7a34c57025372 Mon Sep 17 00:00:00 2001 From: RA <70325462+RAprogramm@users.noreply.github.com> Date: Wed, 17 Sep 2025 07:22:11 +0700 Subject: [PATCH] Use AppResult alias across the crate --- README.md | 4 ++-- src/app_error.rs | 29 ++++++++++++++++++++++++++++- src/convert/actix.rs | 8 +++++--- src/frontend.rs | 14 +++++++------- src/lib.rs | 2 +- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 1204bcc..a920457 100644 --- a/README.md +++ b/README.md @@ -172,10 +172,10 @@ utoipa = "5" ~~~rust // features = ["frontend"] -use masterror::{AppError, AppErrorKind}; +use masterror::{AppError, AppErrorKind, AppResult}; use masterror::frontend::{BrowserConsoleError, BrowserConsoleExt}; -fn report() -> Result<(), BrowserConsoleError> { +fn report() -> AppResult<(), BrowserConsoleError> { let err = AppError::bad_request("missing field"); let payload = err.to_js_value()?; assert!(payload.is_object()); diff --git a/src/app_error.rs b/src/app_error.rs index 8531673..9db9fad 100644 --- a/src/app_error.rs +++ b/src/app_error.rs @@ -83,7 +83,29 @@ pub struct AppError { } /// Conventional result alias for application code. -pub type AppResult = Result; +/// +/// The alias defaults to [`AppError`] but accepts a custom error type when the +/// context requires a different domain error. +/// +/// # Examples +/// +/// ```rust +/// use std::io::Error; +/// +/// use masterror::AppResult; +/// +/// fn app_logic() -> AppResult { +/// Ok(7) +/// } +/// +/// fn io_logic() -> AppResult<(), Error> { +/// Ok(()) +/// } +/// +/// assert_eq!(app_logic().unwrap(), 7); +/// assert!(io_logic().is_ok()); +/// ``` +pub type AppResult = Result; impl AppError { /// Create a new [`AppError`] with a kind and message. @@ -526,15 +548,20 @@ mod tests { fn err() -> AppResult { Err(AppError::internal("x")) } + fn other_err() -> AppResult { + Err("boom") + } let a: AppResult = ok(); let b: AppResult = err(); + let c: AppResult = other_err(); assert_eq!(a.unwrap(), 1); assert!(b.is_err()); if let Err(e) = b { assert!(matches!(e.kind, AppErrorKind::Internal)); } + assert_eq!(c.unwrap_err(), "boom"); } // --- Logging path sanity check ------------------------------------------- diff --git a/src/convert/actix.rs b/src/convert/actix.rs index eb1c7e1..268e60a 100644 --- a/src/convert/actix.rs +++ b/src/convert/actix.rs @@ -35,8 +35,10 @@ //! Err(AppError::new(AppErrorKind::Forbidden, "no access")) //! } //! +//! use std::io::Error; +//! //! #[actix_web::main] -//! async fn main() -> std::io::Result<()> { +//! async fn main() -> AppResult<(), Error> { //! HttpServer::new(|| App::new().service(forbidden)) //! .bind(("127.0.0.1", 8080))? //! .run() @@ -103,7 +105,7 @@ mod actix_tests { http::header::{RETRY_AFTER, WWW_AUTHENTICATE} }; - use crate::{AppCode, AppError, AppErrorKind, ErrorResponse}; + use crate::{AppCode, AppError, AppErrorKind, AppResult, ErrorResponse}; #[test] fn maps_status_consistently() { @@ -112,7 +114,7 @@ mod actix_tests { } #[actix_web::test] // ← вот это - async fn error_response_sets_body_and_headers() -> Result<(), Box> { + async fn error_response_sets_body_and_headers() -> AppResult<(), Box> { let err = AppError::unauthorized("no token") .with_retry_after_secs(7) .with_www_authenticate("Bearer"); diff --git a/src/frontend.rs b/src/frontend.rs index 1083b18..44ac396 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -42,7 +42,7 @@ use thiserror::Error; use wasm_bindgen::JsCast; use wasm_bindgen::JsValue; -use crate::{AppError, ErrorResponse}; +use crate::{AppError, AppResult, ErrorResponse}; /// Error returned when emitting to the browser console fails or is unsupported. #[derive(Debug, Error, PartialEq, Eq)] @@ -85,20 +85,20 @@ pub enum BrowserConsoleError { #[cfg_attr(docsrs, doc(cfg(feature = "frontend")))] pub trait BrowserConsoleExt { /// Convert the error into a [`JsValue`] suitable for passing to JavaScript. - fn to_js_value(&self) -> Result; + fn to_js_value(&self) -> AppResult; /// Emit the error as a structured payload via `console.error`. /// /// On non-WASM targets this returns /// [`BrowserConsoleError::UnsupportedTarget`]. - fn log_to_browser_console(&self) -> Result<(), BrowserConsoleError> { + fn log_to_browser_console(&self) -> AppResult<(), BrowserConsoleError> { let payload = self.to_js_value()?; log_js_value(&payload) } } impl BrowserConsoleExt for ErrorResponse { - fn to_js_value(&self) -> Result { + fn to_js_value(&self) -> AppResult { #[cfg(target_arch = "wasm32")] { to_value(self).map_err(|err| BrowserConsoleError::Serialization { @@ -114,7 +114,7 @@ impl BrowserConsoleExt for ErrorResponse { } impl BrowserConsoleExt for AppError { - fn to_js_value(&self) -> Result { + fn to_js_value(&self) -> AppResult { #[cfg(target_arch = "wasm32")] { let response: ErrorResponse = self.into(); @@ -129,7 +129,7 @@ impl BrowserConsoleExt for AppError { } #[cfg(target_arch = "wasm32")] -fn log_js_value(value: &JsValue) -> Result<(), BrowserConsoleError> { +fn log_js_value(value: &JsValue) -> AppResult<(), BrowserConsoleError> { let global = js_sys::global(); let console = Reflect::get(&global, &JsValue::from_str("console")).map_err(|err| { BrowserConsoleError::ConsoleUnavailable { @@ -168,7 +168,7 @@ fn log_js_value(value: &JsValue) -> Result<(), BrowserConsoleError> { } #[cfg(not(target_arch = "wasm32"))] -fn log_js_value(_value: &JsValue) -> Result<(), BrowserConsoleError> { +fn log_js_value(_value: &JsValue) -> AppResult<(), BrowserConsoleError> { Err(BrowserConsoleError::UnsupportedTarget) } diff --git a/src/lib.rs b/src/lib.rs index 1e0fa0f..8871b71 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ //! - [`AppError`] — thin wrapper around a semantic error kind and optional //! message //! - [`AppErrorKind`] — stable internal taxonomy of application errors -//! - [`AppResult`] — convenience alias for returning [`AppError`] +//! - [`AppResult`] — convenience result alias (defaults to [`AppError`]) //! - [`ErrorResponse`] — stable wire-level JSON payload for HTTP APIs //! - [`AppCode`] — public, machine-readable error code for clients //!