use async_from::{ async_trait, AsyncFrom, AsyncInto, AsyncTryFrom, AsyncTryInto };
#[ tokio::test( flavor = "multi_thread", worker_threads = 2 ) ]
async fn test_async_from_send_bounds()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
tokio::time::sleep( tokio::time::Duration::from_millis( 1 ) ).await;
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let handle = tokio::spawn( async move
{
let num = MyNumber::async_from( "42".to_string() ).await;
num.0
} );
let result = handle.await.expect( "Task should complete successfully" );
assert_eq!( result, 42, "`AsyncFrom` should work with Send bounds across threads" );
}
#[ tokio::test( flavor = "multi_thread", worker_threads = 2 ) ]
async fn test_async_into_send_bounds()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
tokio::time::sleep( tokio::time::Duration::from_millis( 1 ) ).await;
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let handle = tokio::spawn( async move
{
let num : MyNumber = "42".to_string().async_into().await;
num.0
} );
let result = handle.await.expect( "Task should complete successfully" );
assert_eq!( result, 42, "`AsyncInto` should work with Send bounds across threads" );
}
#[ tokio::test( flavor = "multi_thread", worker_threads = 2 ) ]
async fn test_async_try_from_send_bounds()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncTryFrom< String > for MyNumber
{
type Error = core::num::ParseIntError;
async fn async_try_from( value : String ) -> Result< Self, Self::Error >
{
tokio::time::sleep( tokio::time::Duration::from_millis( 1 ) ).await;
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let handle = tokio::spawn( async move
{
MyNumber::async_try_from( "42".to_string() ).await
} );
let result = handle.await.expect( "Task should complete successfully" );
assert!( result.is_ok(), "`AsyncTryFrom` should work with Send bounds across threads" );
assert_eq!( result.unwrap().0, 42, "Result should be 42" );
}
#[ tokio::test( flavor = "multi_thread", worker_threads = 2 ) ]
async fn test_async_try_into_send_bounds()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncTryFrom< String > for MyNumber
{
type Error = core::num::ParseIntError;
async fn async_try_from( value : String ) -> Result< Self, Self::Error >
{
tokio::time::sleep( tokio::time::Duration::from_millis( 1 ) ).await;
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let handle = tokio::spawn( async move
{
let result : Result< MyNumber, _ > = "42".to_string().async_try_into().await;
result
} );
let result = handle.await.expect( "Task should complete successfully" );
assert!( result.is_ok(), "`AsyncTryInto` should work with Send bounds across threads" );
assert_eq!( result.unwrap().0, 42, "Result should be 42" );
}
#[ tokio::test( flavor = "multi_thread", worker_threads = 4 ) ]
async fn test_concurrent_multi_threaded_conversions()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
tokio::time::sleep( tokio::time::Duration::from_millis( 5 ) ).await;
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let handles : Vec< _ > = ( 0..10 )
.map( | i |
{
tokio::spawn( async move
{
let num = MyNumber::async_from( format!( "{}", i * 10 ) ).await;
num.0
} )
} )
.collect();
let results : Vec< u32 > = futures::future::join_all( handles )
.await
.into_iter()
.map( | r | r.expect( "Task should complete" ) )
.collect();
assert_eq!( results.len(), 10, "All 10 tasks should complete" );
for ( i, &result ) in results.iter().enumerate()
{
let expected = u32::try_from( i ).unwrap() * 10;
assert_eq!( result, expected, "Task {} should produce {}", i, i * 10 );
}
}