Skip to main content

zrx_scheduler/scheduler/step/error/
convert.rs

1// Copyright (c) 2025-2026 Zensical and contributors
2
3// SPDX-License-Identifier: MIT
4// Third-party contributions licensed under DCO
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to
8// deal in the Software without restriction, including without limitation the
9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10// sell copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22// IN THE SOFTWARE.
23
24// ----------------------------------------------------------------------------
25
26//! Step error conversions.
27
28use std::error;
29
30use crate::scheduler::signal::Value;
31
32use super::Error;
33
34// ----------------------------------------------------------------------------
35// Traits
36// ----------------------------------------------------------------------------
37
38/// Conversion into [`Error`].
39pub trait IntoError {
40    /// Converts into a step error.
41    ///
42    /// This method is intended to be used within [`Action::execute`][], to make
43    /// it convenient to convert an arbitrary error into a step error.
44    ///
45    /// [`Action::execute`]: crate::scheduler::action::Action::execute
46    fn into_error(self) -> Error;
47}
48
49// ----------------------------------------------------------------------------
50
51/// Conversion into [`Result`].
52pub trait IntoResult<T = ()>: Sized {
53    /// Converts into a step result.
54    ///
55    /// # Errors
56    ///
57    /// In case conversion fails, an error should be returned.
58    fn into_result(self) -> Result<T, Error>;
59}
60
61// ----------------------------------------------------------------------------
62// Blanket implementations
63// ----------------------------------------------------------------------------
64
65impl<E> IntoError for E
66where
67    E: error::Error + Send + 'static,
68{
69    /// Converts any error into a step error.
70    ///
71    /// This implementation attempts to downcast the error into one of the known
72    /// variants, and falls back to the [`Error::Other`] variant in other cases.
73    /// It also ensures that the error is not double-boxed, returning unknown
74    /// errors captured by the [`Error::Other`] variant unchanged.
75    #[inline]
76    fn into_error(self) -> Error {
77        let mut err: Box<dyn error::Error + Send> = Box::new(self);
78        err = match err.downcast() {
79            Ok(err) => return *err,
80            Err(err) => err,
81        };
82
83        // Implements downcast attempt of error
84        macro_rules! downcast {
85            ($variant:path) => {
86                err = match err.downcast() {
87                    Ok(err) => return $variant(*err),
88                    Err(err) => err,
89                }
90            };
91        }
92
93        // Downcast known error variants
94        downcast!(Error::Session);
95        downcast!(Error::Key);
96
97        // Handle unknown error variants
98        Error::Other(err)
99    }
100}
101
102// ----------------------------------------------------------------------------
103
104impl<T, E> IntoResult<T> for Result<T, E>
105where
106    T: Value,
107    E: IntoError,
108{
109    /// Converts any result into a step result.
110    #[inline]
111    fn into_result(self) -> Result<T, Error> {
112        self.map_err(IntoError::into_error)
113    }
114}
115
116impl<T> IntoResult<T> for T
117where
118    T: Value,
119{
120    /// Converts any value into a step result.
121    #[inline]
122    fn into_result(self) -> Result<T, Error> {
123        Ok(self)
124    }
125}