Skip to main content

qubit_error/lang/error/
into_box_error.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Boxed Error Conversion
10//!
11//! Provides an extension trait for explicitly boxing concrete error values.
12//!
13//! Many `BoxResult<T>` functions can rely on the `?` operator to convert
14//! concrete errors into [`BoxError`]. `IntoBoxError` covers the cases where the
15//! conversion must be written as an expression, such as `map_err` closures or
16//! manually constructed `Err` values.
17//!
18//! # Author
19//!
20//! Haixing Hu
21
22use std::error::Error;
23
24use super::BoxError;
25
26/// Extension trait for converting concrete errors into [`BoxError`].
27///
28/// In many `BoxResult<T>` functions, the `?` operator can perform this
29/// conversion automatically. This trait is useful when a call site needs an
30/// explicit conversion, for example inside `map_err`.
31///
32/// # Design Rationale
33///
34/// The standard conversion from a concrete error to `Box<dyn Error + ...>` is
35/// available through `From`, but writing it explicitly often requires a verbose
36/// cast. This trait gives the conversion a project-specific name and keeps call
37/// sites readable:
38///
39/// ```rust
40/// # use qubit_error::error::IntoBoxError;
41/// # fn demo() -> qubit_error::error::BoxResult<u16> {
42/// let port = "8080"
43///     .parse::<u16>()
44///     .map_err(|error| error.into_box_error())?;
45/// # Ok(port)
46/// # }
47/// ```
48///
49/// # When to Use
50///
51/// Use `IntoBoxError` when a concrete error must be converted explicitly. If a
52/// function already returns [`BoxResult`](super::BoxResult), prefer plain `?`
53/// when inference is clear.
54///
55/// # Examples
56///
57/// Explicit conversion in `map_err`:
58///
59/// ```rust
60/// use qubit_error::error::{BoxResult, IntoBoxError};
61///
62/// fn parse_port(text: &str) -> BoxResult<u16> {
63///     text.parse::<u16>()
64///         .map_err(|error| error.into_box_error())
65/// }
66///
67/// assert_eq!(parse_port("8080").expect("valid port"), 8080);
68/// assert!(parse_port("not-a-port").is_err());
69/// ```
70///
71/// Manual `Err` construction:
72///
73/// ```rust
74/// use std::io;
75///
76/// use qubit_error::error::{BoxResult, IntoBoxError};
77///
78/// fn require_enabled(enabled: bool) -> BoxResult<()> {
79///     if enabled {
80///         Ok(())
81///     } else {
82///         Err(io::Error::other("feature disabled").into_box_error())
83///     }
84/// }
85///
86/// assert!(require_enabled(true).is_ok());
87/// assert_eq!(
88///     require_enabled(false)
89///         .expect_err("disabled feature should fail")
90///         .to_string(),
91///     "feature disabled"
92/// );
93/// ```
94pub trait IntoBoxError: Error + Send + Sync + 'static + Sized {
95    /// Converts this error into a boxed dynamic error.
96    ///
97    /// # Returns
98    ///
99    /// A [`BoxError`] preserving this error as the boxed source value.
100    ///
101    /// # Allocation
102    ///
103    /// This method allocates one `Box` and stores `self` as the boxed concrete
104    /// source error. It does not perform I/O, block, or otherwise inspect the
105    /// error value.
106    #[inline]
107    fn into_box_error(self) -> BoxError {
108        Box::new(self)
109    }
110}
111
112impl<E> IntoBoxError for E where E: Error + Send + Sync + 'static {}