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 {}