zrx_diagnostic/diagnostic/report/convert.rs
1// Copyright (c) Zensical LLC <https://zensical.org>
2
3// SPDX-License-Identifier: MIT
4// Third-party contributions licensed under CLA
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//! Report conversions.
27
28use std::error::Error;
29use std::result::Result;
30
31use super::Report;
32
33// ----------------------------------------------------------------------------
34// Traits
35// ----------------------------------------------------------------------------
36
37/// Conversion into [`Report`]
38///
39/// This trait is generic over the [`Ok`] and [`Err`] variants of any result,
40/// which means downstream consumers can implement this trait for custom types,
41/// allowing them to convert any type into a report. It's primarily intended to
42/// support adding diagnostics to fallible as well as infallible methods.
43///
44/// Note that the trait implementations provided here may not include sufficient
45/// trait bounds, which makes explicit annotations necessary in some cases. For
46/// this reason, downstream crates are recommended to provide their own custom
47/// implementation of this trait, adding additional trait bounds on `T`.
48pub trait IntoReport<T, E>
49where
50 E: Error,
51{
52 /// Converts into a report.
53 ///
54 /// # Errors
55 ///
56 /// Note that this method never returns an error by itself, as this trait is
57 /// primarily provided for wrapping values returned from infallible methods.
58 /// Consequentially, this trait isn't named `TryIntoReport`, as it's not
59 /// falling under Rust's try-semantics.
60 fn into_report(self) -> Result<Report<T>, E>;
61}
62
63// ----------------------------------------------------------------------------
64// Blanket implementations
65// ----------------------------------------------------------------------------
66
67impl<T, E> IntoReport<T, E> for T
68where
69 E: Error,
70{
71 /// Creates a report from a value `T` and wraps it in a result.
72 ///
73 /// # Examples
74 ///
75 /// ```
76 /// use std::io::Error;
77 /// use zrx_diagnostic::report::IntoReport;
78 ///
79 /// // Define function returning a value
80 /// fn f() -> impl IntoReport<i32, Error> {
81 /// 42
82 /// }
83 ///
84 /// // Invoke function and create report
85 /// let res = f().into_report();
86 /// ```
87 #[inline]
88 fn into_report(self) -> Result<Report<T>, E> {
89 Ok(Report::new(self))
90 }
91}
92
93impl<T, E> IntoReport<T, E> for Result<T, E>
94where
95 E: Error,
96{
97 /// Creates a report from a value `T` in a result.
98 ///
99 /// # Examples
100 ///
101 /// ```
102 /// use std::io::Error;
103 /// use zrx_diagnostic::report::IntoReport;
104 ///
105 /// // Define function returning a result
106 /// fn f() -> impl IntoReport<i32, Error> {
107 /// Ok(42)
108 /// }
109 ///
110 /// // Invoke function and create report
111 /// let res = f().into_report();
112 /// ```
113 #[inline]
114 fn into_report(self) -> Result<Report<T>, E> {
115 self.map(Report::new)
116 }
117}
118
119impl<T, E> IntoReport<T, E> for Result<Report<T>, E>
120where
121 E: Error,
122{
123 /// Returns the report in a result as is.
124 #[inline]
125 fn into_report(self) -> Result<Report<T>, E> {
126 self
127 }
128}