@ -105,3 +105,73 @@ pub fn alloc_local_with_default<T: Default, U>(sz: usize, within: impl FnOnce(&m
stackalloc ::stackalloc_with_default ( sz , within )
}
}
/// Create a blanket-implementing trait that is a subtrait of any number of traits.
///
/// # Usage
/// To subtype a trait with `Sized` types only:
/// ```
/// # use rsh::subtrait;
/// subtrait!(pub SizedUnpinAsyncRead; "This subtrait must be sized": std::marker::Unpin + tokio::io::AsyncRead);
/// ```
/// To impl the trait for unsized types as well:
/// ```
/// # use rsh::subtrait;
/// subtrait!(pub dyn UnsizedUnpinAsyncRead; "Subtraits `Unpin` and `AsyncRead`. Also implemented for unsized types.": std::marker::Unpin + tokio::io::AsyncRead);
/// ```
/// # Downcastable subtrait
/// To create a subtrait that can be downcasted (correctly coerces to `dyn Any`), use the `virtual` keyword.
/// ```
/// # use rsh::subtrait;
/// subtrait!(pub virtual DowncastableUnpinAsyncRead; "Subtraits `Unpin` and `AsyncRead`. Also dynamically downcastable": std::marker::Unpin + tokio::io::AsyncRead);
/// subtrait!(pub virtual AnotherAny; "A dynamically downcastable trait that subtraits nothing else but `Any`");
/// ```
#[ macro_export ] macro_rules! subtrait {
( @ $v :vis $name :ident $( ; $doc :literal ) ? : $( $t :path ) , + ) = > {
$( #[ doc = $doc ] ) ?
$v trait $name : $( $t + ) + { }
} ;
( $v :vis $name :ident $( ; $doc :literal ) ? : $( $t :path ) , + ) = > {
$crate ::subtrait ! ( @ $v $name $( ; $doc ) ? : Sized , $( $t ) , + ) ;
impl < T : $( $t + ) + > $name for T { }
} ;
( $v :vis dyn $name :ident $( ; $doc :literal ) ? : $( $t :path ) , + ) = > {
$crate ::subtrait ! ( @ $v $name $( ; $doc ) ? : $( $t ) , + ) ;
impl < T : ? Sized + $( $t + ) + > $name for T { }
} ;
( $v :vis virtual $name :ident $( ; $doc :literal ) ? $( : $( $t :path ) , * ) ? ) = > {
$crate ::subtrait ! ( @ $v $name $( ; $doc ) ? : ::mopa ::Any $(, $( $t ) , * ) ? ) ;
const _ :( ) = {
fn _assert_object_safe ( _ : & dyn $name ) { }
} ;
mopafy ! ( $name ) ;
impl < T : ? Sized + ::mopa ::Any $( + $( $t + ) + ) ? > $name for T { }
} ;
}
// Static testing of `subtrait`
const _ :( ) = {
use mopa ::* ;
subtrait ! ( dyn Test ; "test dynamic subtrait" : std ::marker ::Unpin ) ;
subtrait ! ( virtual TestAny ; "test downcastable subtrait of `Read` and `Write`" : std ::io ::Read ) ;
subtrait ! ( virtual TestAny2 ; "test downcastable subtrait of only `Any`" ) ;
const fn _a < T : Test + ? Sized > ( ) { }
const fn _b < T : TestAny + ? Sized > ( ) { }
fn _c ( a : Box < dyn TestAny > )
{
if a . is ::< std ::io ::Stdin > ( ) {
let _ref : & std ::io ::Stdin = a . downcast_ref ::< std ::io ::Stdin > ( ) . unwrap ( ) ;
drop ( _ref ) ;
let _unbox : std ::io ::Stdin = * a . downcast ( ) . map_err ( | _ | ( ) ) . unwrap ( ) ;
}
}
fn _d ( a : & dyn TestAny )
{
if a . is ::< std ::io ::Stdin > ( ) {
let _ref : & std ::io ::Stdin = a . downcast_ref ::< std ::io ::Stdin > ( ) . unwrap ( ) ;
}
}
const _TEST : ( ) = _a ::< dyn Test > ( ) ;
const _TEST2 : ( ) = _b ::< dyn TestAny > ( ) ;
} ;