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