#![ cfg( all( feature = "async_from", feature = "async_try_from" ) ) ]
use async_from::{ async_trait, AsyncFrom, AsyncInto, AsyncTryFrom, AsyncTryInto };
#[ tokio::test ]
async fn readme_example_async_from()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let num = MyNumber::async_from( "42".to_string() ).await;
assert_eq!( num.0, 42, "AsyncFrom should convert '42' to 42" );
let num : MyNumber = "42".to_string().async_into().await;
assert_eq!( num.0, 42, "AsyncInto should convert '42' to 42" );
}
#[ tokio::test ]
async fn readme_example_async_try_from()
{
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 >
{
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let result = MyNumber::async_try_from( "42".to_string() ).await;
assert!( result.is_ok(), "AsyncTryFrom should succeed for valid input" );
assert_eq!( result.unwrap().0, 42, "AsyncTryFrom should convert '42' to 42" );
let result : Result< MyNumber, _ > = "42".to_string().async_try_into().await;
assert!( result.is_ok(), "AsyncTryInto should succeed for valid input" );
assert_eq!( result.unwrap().0, 42, "AsyncTryInto should convert '42' to 42" );
}
#[ tokio::test ]
async fn async_try_from_leading_zeros()
{
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 >
{
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let result = MyNumber::async_try_from( "0042".to_string() ).await;
assert!( result.is_ok(), "Leading zeros should parse successfully" );
assert_eq!( result.unwrap().0, 42, "0042 should convert to 42" );
}
#[ tokio::test ]
async fn async_try_from_spaces()
{
#[ allow( dead_code ) ]
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 >
{
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let result = MyNumber::async_try_from( " 42 ".to_string() ).await;
assert!( result.is_err(), "Leading/trailing spaces should be rejected" );
let result = MyNumber::async_try_from( " 42".to_string() ).await;
assert!( result.is_err(), "Leading space should be rejected" );
let result = MyNumber::async_try_from( "42 ".to_string() ).await;
assert!( result.is_err(), "Trailing space should be rejected" );
}
#[ tokio::test ]
async fn async_try_from_float_format()
{
#[ allow( dead_code ) ]
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 >
{
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let result = MyNumber::async_try_from( "42.5".to_string() ).await;
assert!( result.is_err(), "Float format should be rejected for u32" );
let result = MyNumber::async_try_from( "42.0".to_string() ).await;
assert!( result.is_err(), "Float format with .0 should be rejected for u32" );
}
#[ tokio::test ]
async fn async_try_from_scientific_notation()
{
#[ allow( dead_code ) ]
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 >
{
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let result = MyNumber::async_try_from( "4.2e1".to_string() ).await;
assert!( result.is_err(), "Scientific notation should be rejected" );
let result = MyNumber::async_try_from( "1e2".to_string() ).await;
assert!( result.is_err(), "Scientific notation should be rejected" );
}
#[ tokio::test ]
async fn async_try_from_plus_sign()
{
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 >
{
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let result = MyNumber::async_try_from( "+42".to_string() ).await;
assert!( result.is_ok(), "Plus sign should be accepted for u32" );
assert_eq!( result.unwrap().0, 42, "+42 should parse to 42" );
}
#[ tokio::test ]
async fn async_try_from_unicode_digits()
{
#[ allow( dead_code ) ]
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 >
{
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let result = MyNumber::async_try_from( "٤٢".to_string() ).await;
assert!( result.is_err(), "Unicode digits should be rejected" );
}
#[ tokio::test ]
async fn async_try_from_hex_format()
{
#[ allow( dead_code ) ]
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 >
{
let num = value.parse::< u32 >()?;
Ok( MyNumber( num ) )
}
}
let result = MyNumber::async_try_from( "0x2A".to_string() ).await;
assert!( result.is_err(), "Hex format should be rejected by default parse()" );
}
#[ tokio::test ]
async fn async_from_leading_zeros()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let num = MyNumber::async_from( "0042".to_string() ).await;
assert_eq!( num.0, 42, "0042 should convert to 42" );
}
#[ tokio::test ]
async fn async_from_spaces()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let num = MyNumber::async_from( " 42 ".to_string() ).await;
assert_eq!( num.0, 0, "Spaces should fallback to 0" );
let num = MyNumber::async_from( " 42".to_string() ).await;
assert_eq!( num.0, 0, "Leading space should fallback to 0" );
let num = MyNumber::async_from( "42 ".to_string() ).await;
assert_eq!( num.0, 0, "Trailing space should fallback to 0" );
}
#[ tokio::test ]
async fn async_from_negative()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let num = MyNumber::async_from( "-1".to_string() ).await;
assert_eq!( num.0, 0, "Negative value should fallback to 0" );
let num = MyNumber::async_from( "-42".to_string() ).await;
assert_eq!( num.0, 0, "Negative value should fallback to 0" );
}
#[ tokio::test ]
async fn async_from_overflow()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let num = MyNumber::async_from( "99999999999999".to_string() ).await;
assert_eq!( num.0, 0, "Overflow should fallback to 0" );
}
#[ tokio::test ]
async fn async_from_max_value()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
let num = value.parse::< u32 >().unwrap_or( 0 );
MyNumber( num )
}
}
let max_str = u32::MAX.to_string();
let num = MyNumber::async_from( max_str ).await;
assert_eq!( num.0, u32::MAX, "u32::MAX should parse correctly" );
}
#[ tokio::test ]
async fn async_from_zero()
{
struct MyNumber( u32 );
#[ async_trait ]
impl AsyncFrom< String > for MyNumber
{
async fn async_from( value : String ) -> Self
{
let num = value.parse::< u32 >().unwrap_or( 999 ); MyNumber( num )
}
}
let num = MyNumber::async_from( "0".to_string() ).await;
assert_eq!( num.0, 0, "Zero should parse to 0, not fallback" );
}