async_reciprocals/
api.rs

1/// Provides asynchronous, fallible type conversion traits and utilities.
2///
3/// This module defines two primary traits:
4/// - `AsyncTryFrom`: Allows asynchronous conversion from one type to another that may fail
5/// - `AsyncTryInto`: Enables asynchronous conversion attempts with potential failure
6///
7/// The traits support async conversion operations similar to standard `TryFrom` and `TryInto`,
8/// but with asynchronous semantics. They include blanket implementations and helper methods
9/// to simplify conversion between types in async contexts.
10///
11/// # Examples
12///
13///
14/// async fn convert<T: AsyncTryInto<U>>(value: T) -> Result<U, T::Error> {
15///     value.async_try_into().await
16/// }
17///
18///
19/// Provides extension methods and adapters to facilitate flexible type conversions
20/// in asynchronous code.
21use std::marker::PhantomData;
22
23/// Enables asynchronous trait methods by generating boilerplate code for async fn in traits
24///
25/// This macro allows defining async methods in traits, which is not natively supported in Rust.
26/// It automatically generates the necessary associated types and implementation details to make
27/// async trait methods work across different async runtimes.
28///
29/// # Examples
30///
31/// ```
32///
33#[async_trait::async_trait]
34pub trait AsyncTryFrom<T>: Sized {
35    type Error;
36    async fn async_try_from(value: T)
37    -> std::result::Result<Self, Self::Error>;
38}
39
40#[async_trait::async_trait]
41/// A trait for performing fallible, asynchronous conversions from one type to another.
42///
43/// Similar to `TryInto`, but with support for asynchronous conversion operations.
44/// Allows a type to be converted into another type, with the possibility of failure,
45/// using an asynchronous method.
46///
47/// # Examples
48///
49///
50/// async fn convert<T: AsyncTryInto<U>>(value: T) -> Result<U, T::Error> {
51///     value.async_try_into().await
52/// }
53///
54pub trait AsyncTryInto<T>: Sized {
55    type Error;
56    #[allow(dead_code)]
57    async fn async_try_into(self) -> std::result::Result<T, Self::Error>;
58}
59
60#[allow(dead_code)]
61/// An adapter struct for facilitating asynchronous type conversions from one type to another.
62///
63/// This zero-sized type uses `PhantomData` to represent a conversion between generic types `T` and `U`,
64/// providing a marker for conversion-related operations in asynchronous contexts.
65///
66/// # Examples
67///
68///
69/// // Used as a type-level marker for async conversion strategies
70/// let _adapter = FromAdapter::<SourceType, TargetType>(PhantomData);
71///
72pub struct FromAdapter<T, U>(PhantomData<(T, U)>);
73
74#[allow(dead_code)]
75/// An adapter struct for facilitating asynchronous type conversions to another type.
76///
77/// This zero-sized type uses `PhantomData` to represent a conversion between generic types `T` and `U`,
78/// providing a marker for conversion-related operations in asynchronous contexts.
79///
80/// # Examples
81///
82/// // Used as a type-level marker for async conversion strategies
83/// let _adapter = IntoAdapter::<SourceType, TargetType>(PhantomData);
84pub struct IntoAdapter<T, U>(PhantomData<(T, U)>);
85
86#[async_trait::async_trait]
87/// Provides a generic implementation of `AsyncTryInto` for types that can be converted
88/// asynchronously using `AsyncTryFrom`.
89///
90/// This implementation allows any type `T` to be converted into type `U` if `U` implements
91/// `AsyncTryFrom<T>`. The conversion is performed asynchronously and can potentially fail.
92///
93/// # Type Parameters
94///
95/// - `T`: The source type being converted from
96/// - `U`: The target type being converted into
97///
98/// # Constraints
99///
100/// - `U` must implement `AsyncTryFrom<T>`
101/// - `T` must be `Send`
102///
103/// # Returns
104///
105/// A `Result` containing the converted value or an error if the conversion fails
106impl<T, U> AsyncTryInto<U> for T
107where
108    U: AsyncTryFrom<T>,
109    T: Send,
110{
111    type Error = U::Error;
112
113    async fn async_try_into(self) -> std::result::Result<U, Self::Error> {
114        U::async_try_from(self).await
115    }
116}
117
118#[async_trait::async_trait]
119/// Provides a trivial implementation of `AsyncTryFrom` for a type converting to itself.
120///
121/// This implementation allows any `Send` type to be converted asynchronously to itself
122/// without any possibility of failure, always returning `Ok(value)`.
123///
124/// # Type Parameters
125///
126/// - `T`: The type being converted, which must implement `Send`
127///
128/// # Returns
129///
130/// Always returns `Ok(value)` with an `Infallible` error type, representing a guaranteed successful conversion
131impl<T: Send> AsyncTryFrom<T> for T {
132    type Error = std::convert::Infallible;
133
134    async fn async_try_from(
135        value: T,
136    ) -> std::result::Result<Self, Self::Error> {
137        Ok(value)
138    }
139}
140
141// If user implements AsyncTryInto, they can use this adapter to get AsyncTryFrom
142// #[async_trait::async_trait]
143// impl<T, U> AsyncTryFrom<U> for T
144// where
145//     U: AsyncTryInto<T>,
146//     U: Send,
147// {
148//     type Error = U::Error;
149
150//     async fn async_try_from(value: U) -> std::result::Result<T, Self::Error>
151//     where
152//         U: 'async_trait,
153//     {
154//         value.async_try_into().await
155//     }
156// }
157
158/// Extension methods and utilities for asynchronous type conversions
159///
160/// This module provides additional functionality and helper methods
161/// for working with asynchronous type conversion traits like `AsyncTryFrom` and `AsyncTryInto`.
162pub mod extensions {
163    use super::*;
164
165    #[allow(dead_code)]
166    /// Creates a `FromAdapter` for converting between types using `AsyncTryFrom`.
167    ///
168    /// This utility function helps in creating type adapters for asynchronous conversions
169    /// between different types that implement `AsyncTryFrom`.
170    ///
171    /// # Type Parameters
172    ///
173    /// - `T`: The source type being converted from
174    /// - `U`: The target type being converted to
175    ///
176    /// # Returns
177    ///
178    /// A `FromAdapter` that can be used for type conversions
179    pub fn from_to_into<T, U>(_: &impl AsyncTryFrom<T>) -> FromAdapter<T, U> {
180        FromAdapter(PhantomData)
181    }
182
183    #[allow(dead_code)]
184    /// Creates an `IntoAdapter` for converting between types using `AsyncTryInto`.
185    ///
186    /// This utility function helps in creating type adapters for asynchronous conversions
187    /// between different types that implement `AsyncTryInto`.
188    ///
189    /// # Type Parameters
190    ///
191    /// - `T`: The source type being converted from
192    /// - `U`: The target type being converted to
193    ///
194    /// # Returns
195    ///
196    /// An `IntoAdapter` that can be used for type conversions
197    pub fn into_to_from<T, U>(_: &impl AsyncTryInto<U>) -> IntoAdapter<T, U> {
198        IntoAdapter(PhantomData)
199    }
200}
201
202#[cfg(test)]
203mod tests {
204    use super::*;
205    use std::error::Error;
206
207    // Existing tests...
208
209    // Test AsyncTryFrom and AsyncTryInto separately to avoid conflicts
210    mod async_try_from_tests {
211
212        use super::*;
213
214        struct TestFromType(String);
215
216        #[async_trait::async_trait]
217        impl AsyncTryFrom<String> for TestFromType {
218            type Error = Box<dyn Error>;
219
220            async fn async_try_from(
221                value: String,
222            ) -> std::result::Result<Self, Self::Error> {
223                Ok(TestFromType(value))
224            }
225        }
226
227        #[tokio::test]
228        async fn test_async_try_from_and_into() {
229            // Test direct AsyncTryFrom usage
230            let input = "test string".to_string();
231            let result = TestFromType::async_try_from(input.clone()).await;
232            assert!(result.is_ok());
233            assert_eq!(result.unwrap().0, input);
234
235            // Test that AsyncTryInto is automatically available through blanket impl
236            let input = "another test".to_string();
237            let result: Result<TestFromType, _> = input.async_try_into().await;
238            assert!(result.is_ok());
239            assert_eq!(result.unwrap().0, "another test");
240        }
241    }
242
243    mod async_try_into_tests {
244        use super::*;
245        use std::error::Error;
246
247        struct TestIntoType(String);
248
249        #[async_trait::async_trait]
250        impl AsyncTryInto<String> for TestIntoType {
251            type Error = Box<dyn Error>;
252
253            async fn async_try_into(
254                self,
255            ) -> std::result::Result<String, Self::Error> {
256                Ok(self.0)
257            }
258        }
259
260        #[tokio::test]
261        async fn test_async_try_into_and_from() {
262            // Test direct AsyncTryInto usage
263            let test_into = TestIntoType("test data".to_string());
264            let result: Result<String, Box<dyn Error>> =
265                test_into.async_try_into().await;
266            assert!(result.is_ok());
267            assert_eq!(result.unwrap(), "test data");
268
269            // Test that AsyncTryFrom is automatically available through blanket impl
270            // No automatic AsyncTryFrom implementation in this direction
271            // Users would need to implement AsyncTryFrom manually if needed
272        }
273    }
274}