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}